sassc 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/ext/libsass/.gitignore +6 -0
- data/ext/libsass/.travis.yml +5 -1
- data/ext/libsass/Makefile +12 -3
- data/ext/libsass/Makefile.am +16 -28
- data/ext/libsass/Readme.md +1 -0
- data/ext/libsass/appveyor.yml +1 -2
- data/ext/libsass/ast.cpp +9 -0
- data/ext/libsass/ast.hpp +152 -55
- data/ext/libsass/ast_factory.hpp +2 -0
- data/ext/libsass/ast_fwd_decl.hpp +1 -0
- data/ext/libsass/backtrace.hpp +2 -2
- data/ext/libsass/bind.cpp +15 -13
- data/ext/libsass/configure.ac +17 -5
- data/ext/libsass/constants.cpp +22 -2
- data/ext/libsass/constants.hpp +21 -2
- data/ext/libsass/context.cpp +79 -57
- data/ext/libsass/context.hpp +23 -9
- data/ext/libsass/contextualize.cpp +2 -28
- data/ext/libsass/contextualize.hpp +6 -10
- data/ext/libsass/contextualize_eval.cpp +93 -0
- data/ext/libsass/contextualize_eval.hpp +44 -0
- data/ext/libsass/contrib/plugin.cpp +57 -0
- data/ext/libsass/cssize.cpp +3 -1
- data/ext/libsass/debugger.hpp +242 -83
- data/ext/libsass/emitter.cpp +1 -1
- data/ext/libsass/emitter.hpp +1 -1
- data/ext/libsass/environment.hpp +109 -25
- data/ext/libsass/error_handling.cpp +3 -3
- data/ext/libsass/error_handling.hpp +0 -1
- data/ext/libsass/eval.cpp +145 -61
- data/ext/libsass/eval.hpp +9 -1
- data/ext/libsass/expand.cpp +134 -60
- data/ext/libsass/expand.hpp +5 -2
- data/ext/libsass/extend.cpp +7 -5
- data/ext/libsass/file.cpp +176 -123
- data/ext/libsass/file.hpp +44 -7
- data/ext/libsass/functions.cpp +36 -17
- data/ext/libsass/functions.hpp +2 -2
- data/ext/libsass/inspect.cpp +23 -14
- data/ext/libsass/inspect.hpp +1 -0
- data/ext/libsass/json.cpp +132 -135
- data/ext/libsass/lexer.cpp +133 -0
- data/ext/libsass/lexer.hpp +239 -0
- data/ext/libsass/listize.cpp +83 -0
- data/ext/libsass/listize.hpp +41 -0
- data/ext/libsass/operation.hpp +2 -0
- data/ext/libsass/output.cpp +5 -6
- data/ext/libsass/parser.cpp +426 -388
- data/ext/libsass/parser.hpp +97 -109
- data/ext/libsass/plugins.cpp +15 -2
- data/ext/libsass/plugins.hpp +6 -4
- data/ext/libsass/position.cpp +52 -17
- data/ext/libsass/position.hpp +19 -17
- data/ext/libsass/prelexer.cpp +202 -235
- data/ext/libsass/prelexer.hpp +73 -333
- data/ext/libsass/sass.cpp +21 -11
- data/ext/libsass/sass.h +6 -6
- data/ext/libsass/sass_context.cpp +167 -81
- data/ext/libsass/sass_context.h +26 -6
- data/ext/libsass/sass_functions.cpp +49 -40
- data/ext/libsass/sass_functions.h +55 -43
- data/ext/libsass/sass_interface.cpp +9 -8
- data/ext/libsass/sass_interface.h +3 -3
- data/ext/libsass/sass_version.h +8 -0
- data/ext/libsass/sass_version.h.in +8 -0
- data/ext/libsass/script/ci-build-libsass +3 -3
- data/ext/libsass/script/ci-report-coverage +2 -1
- data/ext/libsass/source_map.cpp +2 -2
- data/ext/libsass/util.cpp +60 -11
- data/ext/libsass/util.hpp +6 -1
- data/ext/libsass/win/libsass.filters +12 -0
- data/ext/libsass/win/libsass.vcxproj +10 -0
- data/lib/sassc.rb +3 -1
- data/lib/sassc/cache_stores/base.rb +2 -0
- data/lib/sassc/dependency.rb +3 -1
- data/lib/sassc/engine.rb +31 -16
- data/lib/sassc/error.rb +3 -2
- data/lib/sassc/functions_handler.rb +54 -0
- data/lib/sassc/import_handler.rb +41 -0
- data/lib/sassc/importer.rb +4 -31
- data/lib/sassc/native.rb +1 -1
- data/lib/sassc/native/native_context_api.rb +3 -2
- data/lib/sassc/script.rb +0 -51
- data/lib/sassc/version.rb +1 -1
- data/sassc.gemspec +1 -0
- data/test/custom_importer_test.rb +72 -69
- data/test/engine_test.rb +53 -54
- data/test/functions_test.rb +40 -39
- data/test/native_test.rb +145 -149
- data/test/output_style_test.rb +98 -0
- data/test/test_helper.rb +21 -7
- metadata +28 -2
@@ -0,0 +1,41 @@
|
|
1
|
+
#ifndef SASS_LISTIZE_H
|
2
|
+
#define SASS_LISTIZE_H
|
3
|
+
|
4
|
+
#include <vector>
|
5
|
+
#include <iostream>
|
6
|
+
|
7
|
+
#include "ast.hpp"
|
8
|
+
#include "context.hpp"
|
9
|
+
#include "operation.hpp"
|
10
|
+
#include "environment.hpp"
|
11
|
+
|
12
|
+
namespace Sass {
|
13
|
+
using namespace std;
|
14
|
+
|
15
|
+
typedef Environment<AST_Node*> Env;
|
16
|
+
struct Backtrace;
|
17
|
+
|
18
|
+
class Listize : public Operation_CRTP<Expression*, Listize> {
|
19
|
+
|
20
|
+
Context& ctx;
|
21
|
+
|
22
|
+
Expression* fallback_impl(AST_Node* n);
|
23
|
+
|
24
|
+
public:
|
25
|
+
Listize(Context&);
|
26
|
+
virtual ~Listize() { }
|
27
|
+
|
28
|
+
using Operation<Expression*>::operator();
|
29
|
+
|
30
|
+
Expression* operator()(Selector_List*);
|
31
|
+
Expression* operator()(Complex_Selector*);
|
32
|
+
Expression* operator()(Compound_Selector*);
|
33
|
+
Expression* operator()(Selector_Reference*);
|
34
|
+
|
35
|
+
template <typename U>
|
36
|
+
Expression* fallback(U x) { return fallback_impl(x); }
|
37
|
+
};
|
38
|
+
|
39
|
+
}
|
40
|
+
|
41
|
+
#endif
|
data/ext/libsass/operation.hpp
CHANGED
@@ -61,6 +61,7 @@ namespace Sass {
|
|
61
61
|
virtual T operator()(Media_Query_Expression* x) = 0;
|
62
62
|
virtual T operator()(At_Root_Expression* x) = 0;
|
63
63
|
virtual T operator()(Null* x) = 0;
|
64
|
+
virtual T operator()(Parent_Selector* x) = 0;
|
64
65
|
// parameters and arguments
|
65
66
|
virtual T operator()(Parameter* x) = 0;
|
66
67
|
virtual T operator()(Parameters* x) = 0;
|
@@ -135,6 +136,7 @@ namespace Sass {
|
|
135
136
|
virtual T operator()(Media_Query_Expression* x) { return static_cast<D*>(this)->fallback(x); }
|
136
137
|
virtual T operator()(At_Root_Expression* x) { return static_cast<D*>(this)->fallback(x); }
|
137
138
|
virtual T operator()(Null* x) { return static_cast<D*>(this)->fallback(x); }
|
139
|
+
virtual T operator()(Parent_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
138
140
|
// parameters and arguments
|
139
141
|
virtual T operator()(Parameter* x) { return static_cast<D*>(this)->fallback(x); }
|
140
142
|
virtual T operator()(Parameters* x) { return static_cast<D*>(this)->fallback(x); }
|
data/ext/libsass/output.cpp
CHANGED
@@ -134,7 +134,7 @@ namespace Sass {
|
|
134
134
|
String_Constant* valConst = static_cast<String_Constant*>(dec->value());
|
135
135
|
string val(valConst->value());
|
136
136
|
if (dynamic_cast<String_Quoted*>(valConst)) {
|
137
|
-
if (val.empty()) {
|
137
|
+
if (!valConst->quote_mark() && val.empty()) {
|
138
138
|
bPrintExpression = false;
|
139
139
|
}
|
140
140
|
}
|
@@ -172,11 +172,10 @@ namespace Sass {
|
|
172
172
|
|
173
173
|
void Output::operator()(Keyframe_Rule* r)
|
174
174
|
{
|
175
|
-
String* v = r->rules();
|
176
175
|
Block* b = r->block();
|
176
|
+
Selector* v = r->selector();
|
177
177
|
|
178
178
|
if (v) {
|
179
|
-
append_indentation();
|
180
179
|
v->perform(this);
|
181
180
|
}
|
182
181
|
|
@@ -338,9 +337,9 @@ namespace Sass {
|
|
338
337
|
append_token(kwd, a);
|
339
338
|
if (s) {
|
340
339
|
append_mandatory_space();
|
341
|
-
|
340
|
+
in_wrapped = true;
|
342
341
|
s->perform(this);
|
343
|
-
|
342
|
+
in_wrapped = false;
|
344
343
|
}
|
345
344
|
else if (v) {
|
346
345
|
append_mandatory_space();
|
@@ -379,7 +378,7 @@ namespace Sass {
|
|
379
378
|
void Output::operator()(String_Quoted* s)
|
380
379
|
{
|
381
380
|
if (s->quote_mark()) {
|
382
|
-
append_token(quote(
|
381
|
+
append_token(quote(s->value(), s->quote_mark()), s);
|
383
382
|
} else if (!in_comment) {
|
384
383
|
append_token(string_to_output(s->value()), s);
|
385
384
|
} else {
|
data/ext/libsass/parser.cpp
CHANGED
@@ -63,16 +63,25 @@ namespace Sass {
|
|
63
63
|
block_stack.push_back(root);
|
64
64
|
root->is_root(true);
|
65
65
|
read_bom();
|
66
|
+
|
67
|
+
if (ctx.queue.size() == 1) {
|
68
|
+
Import* pre = new (ctx.mem) Import(pstate);
|
69
|
+
string load_path(ctx.queue[0].load_path);
|
70
|
+
do_import(load_path, pre, ctx.c_headers, false);
|
71
|
+
ctx.head_imports = ctx.queue.size() - 1;
|
72
|
+
if (!pre->urls().empty()) (*root) << pre;
|
73
|
+
if (!pre->files().empty()) {
|
74
|
+
for (size_t i = 0, S = pre->files().size(); i < S; ++i) {
|
75
|
+
(*root) << new (ctx.mem) Import_Stub(pstate, pre->files()[i]);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
66
80
|
lex< optional_spaces >();
|
67
81
|
Selector_Lookahead lookahead_result;
|
68
82
|
while (position < end) {
|
69
|
-
|
70
|
-
|
71
|
-
String* contents = parse_interpolated_chunk(lexed);
|
72
|
-
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
73
|
-
(*root) << comment;
|
74
|
-
}
|
75
|
-
else if (peek< import >()) {
|
83
|
+
parse_block_comments(root);
|
84
|
+
if (peek< kwd_import >()) {
|
76
85
|
Import* imp = parse_import();
|
77
86
|
if (!imp->urls().empty()) (*root) << imp;
|
78
87
|
if (!imp->files().empty()) {
|
@@ -82,7 +91,7 @@ namespace Sass {
|
|
82
91
|
}
|
83
92
|
if (!lex< one_plus< exactly<';'> > >()) error("top-level @import directive must be terminated by ';'", pstate);
|
84
93
|
}
|
85
|
-
else if (peek<
|
94
|
+
else if (peek< kwd_mixin >() || peek< kwd_function >()) {
|
86
95
|
(*root) << parse_definition();
|
87
96
|
}
|
88
97
|
else if (peek< variable >()) {
|
@@ -92,41 +101,41 @@ namespace Sass {
|
|
92
101
|
/*else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
|
93
102
|
(*root) << parse_propset();
|
94
103
|
}*/
|
95
|
-
else if (peek<
|
104
|
+
else if (peek< kwd_include >() /* || peek< exactly<'+'> >() */) {
|
96
105
|
Mixin_Call* mixin_call = parse_mixin_call();
|
97
106
|
(*root) << mixin_call;
|
98
107
|
if (!mixin_call->block() && !lex< one_plus< exactly<';'> > >()) error("top-level @include directive must be terminated by ';'", pstate);
|
99
108
|
}
|
100
|
-
else if (peek<
|
109
|
+
else if (peek< kwd_if_directive >()) {
|
101
110
|
(*root) << parse_if_directive();
|
102
111
|
}
|
103
|
-
else if (peek<
|
112
|
+
else if (peek< kwd_for_directive >()) {
|
104
113
|
(*root) << parse_for_directive();
|
105
114
|
}
|
106
|
-
else if (peek<
|
115
|
+
else if (peek< kwd_each_directive >()) {
|
107
116
|
(*root) << parse_each_directive();
|
108
117
|
}
|
109
|
-
else if (peek<
|
118
|
+
else if (peek< kwd_while_directive >()) {
|
110
119
|
(*root) << parse_while_directive();
|
111
120
|
}
|
112
|
-
else if (peek<
|
121
|
+
else if (peek< kwd_media >()) {
|
113
122
|
(*root) << parse_media_block();
|
114
123
|
}
|
115
|
-
else if (peek<
|
124
|
+
else if (peek< kwd_at_root >()) {
|
116
125
|
(*root) << parse_at_root_block();
|
117
126
|
}
|
118
|
-
else if (peek<
|
127
|
+
else if (peek< kwd_supports >()) {
|
119
128
|
(*root) << parse_feature_block();
|
120
129
|
}
|
121
|
-
else if (peek<
|
130
|
+
else if (peek< kwd_warn >()) {
|
122
131
|
(*root) << parse_warning();
|
123
132
|
if (!lex< one_plus< exactly<';'> > >()) error("top-level @warn directive must be terminated by ';'", pstate);
|
124
133
|
}
|
125
|
-
else if (peek<
|
134
|
+
else if (peek< kwd_err >()) {
|
126
135
|
(*root) << parse_error();
|
127
136
|
if (!lex< one_plus< exactly<';'> > >()) error("top-level @error directive must be terminated by ';'", pstate);
|
128
137
|
}
|
129
|
-
else if (peek<
|
138
|
+
else if (peek< kwd_dbg >()) {
|
130
139
|
(*root) << parse_debug();
|
131
140
|
if (!lex< one_plus< exactly<';'> > >()) error("top-level @debug directive must be terminated by ';'", pstate);
|
132
141
|
}
|
@@ -147,9 +156,9 @@ namespace Sass {
|
|
147
156
|
lex< one_plus< exactly<';'> > >();
|
148
157
|
}
|
149
158
|
else {
|
150
|
-
lex<
|
159
|
+
lex< css_whitespace >();
|
151
160
|
if (position >= end) break;
|
152
|
-
error("invalid top-level expression",
|
161
|
+
error("invalid top-level expression", after_token);
|
153
162
|
}
|
154
163
|
lex< optional_spaces >();
|
155
164
|
}
|
@@ -183,90 +192,107 @@ namespace Sass {
|
|
183
192
|
|
184
193
|
}
|
185
194
|
|
195
|
+
void Parser::import_single_file (Import* imp, string import_path) {
|
196
|
+
|
197
|
+
if (!unquote(import_path).substr(0, 7).compare("http://") ||
|
198
|
+
!unquote(import_path).substr(0, 8).compare("https://") ||
|
199
|
+
!unquote(import_path).substr(0, 2).compare("//"))
|
200
|
+
{
|
201
|
+
imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
|
202
|
+
}
|
203
|
+
else {
|
204
|
+
add_single_file(imp, import_path);
|
205
|
+
}
|
206
|
+
|
207
|
+
}
|
208
|
+
|
209
|
+
bool Parser::do_import(const string& import_path, Import* imp, vector<Sass_Importer_Entry> importers, bool only_one)
|
210
|
+
{
|
211
|
+
bool has_import = false;
|
212
|
+
string load_path = unquote(import_path);
|
213
|
+
for (auto importer : importers) {
|
214
|
+
// int priority = sass_importer_get_priority(importer);
|
215
|
+
Sass_Importer_Fn fn = sass_importer_get_function(importer);
|
216
|
+
if (Sass_Import_List includes =
|
217
|
+
fn(load_path.c_str(), importer, ctx.c_compiler)
|
218
|
+
) {
|
219
|
+
Sass_Import_List list = includes;
|
220
|
+
while (*includes) {
|
221
|
+
Sass_Import_Entry include = *includes;
|
222
|
+
const char *file = sass_import_get_path(include);
|
223
|
+
char* source = sass_import_take_source(include);
|
224
|
+
size_t line = sass_import_get_error_line(include);
|
225
|
+
size_t column = sass_import_get_error_column(include);
|
226
|
+
const char* message = sass_import_get_error_message(include);
|
227
|
+
if (message) {
|
228
|
+
if (line == string::npos && column == string::npos) error(message, pstate);
|
229
|
+
else error(message, ParserState(message, source, Position(line, column)));
|
230
|
+
} else if (source) {
|
231
|
+
if (file) {
|
232
|
+
ctx.add_source(file, load_path, source);
|
233
|
+
imp->files().push_back(file);
|
234
|
+
} else {
|
235
|
+
ctx.add_source(load_path, load_path, source);
|
236
|
+
imp->files().push_back(load_path);
|
237
|
+
}
|
238
|
+
} else if(file) {
|
239
|
+
import_single_file(imp, file);
|
240
|
+
}
|
241
|
+
++includes;
|
242
|
+
}
|
243
|
+
// deallocate returned memory
|
244
|
+
sass_delete_import_list(list);
|
245
|
+
// set success flag
|
246
|
+
has_import = true;
|
247
|
+
// break import chain
|
248
|
+
if (only_one) return true;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
// return result
|
252
|
+
return has_import;
|
253
|
+
}
|
254
|
+
|
186
255
|
Import* Parser::parse_import()
|
187
256
|
{
|
188
|
-
lex<
|
257
|
+
lex< kwd_import >();
|
189
258
|
Import* imp = new (ctx.mem) Import(pstate);
|
190
259
|
bool first = true;
|
191
260
|
do {
|
192
261
|
while (lex< block_comment >());
|
193
262
|
if (lex< quoted_string >()) {
|
194
|
-
|
195
|
-
|
196
|
-
// struct Sass_Options opt = sass_context_get_options(ctx)
|
197
|
-
Sass_C_Import_Callback importer = ctx.importer;
|
198
|
-
// custom importer
|
199
|
-
if (importer) {
|
200
|
-
Sass_Import* current = ctx.import_stack.back();
|
201
|
-
Sass_C_Import_Fn fn = sass_import_get_function(importer);
|
202
|
-
void* cookie = sass_import_get_cookie(importer);
|
203
|
-
// create a new import entry
|
204
|
-
string inc_path = unquote(import_path);
|
205
|
-
struct Sass_Import** includes = fn(
|
206
|
-
inc_path.c_str(),
|
207
|
-
sass_import_get_path(current),
|
208
|
-
cookie);
|
209
|
-
if (includes) {
|
210
|
-
struct Sass_Import** list = includes;
|
211
|
-
while (*includes) {
|
212
|
-
struct Sass_Import* include = *includes;
|
213
|
-
const char *file = sass_import_get_path(include);
|
214
|
-
char* source = sass_import_take_source(include);
|
215
|
-
size_t line = sass_import_get_error_line(include);
|
216
|
-
size_t column = sass_import_get_error_column(include);
|
217
|
-
const char* message = sass_import_get_error_message(include);
|
218
|
-
// char *srcmap = sass_import_take_srcmap(include);
|
219
|
-
if (message) {
|
220
|
-
if (line == string::npos && column == string::npos) error(message, pstate);
|
221
|
-
else error(message, ParserState(message, Position(line, column)));
|
222
|
-
} else if (source) {
|
223
|
-
if (file) {
|
224
|
-
ctx.add_source(file, inc_path, source);
|
225
|
-
imp->files().push_back(file);
|
226
|
-
} else {
|
227
|
-
ctx.add_source(inc_path, inc_path, source);
|
228
|
-
imp->files().push_back(inc_path);
|
229
|
-
}
|
230
|
-
} else if(file) {
|
231
|
-
add_single_file(imp, file);
|
232
|
-
}
|
233
|
-
++includes;
|
234
|
-
}
|
235
|
-
// deallocate returned memory
|
236
|
-
sass_delete_import_list(list);
|
237
|
-
// parse next import
|
238
|
-
continue;
|
239
|
-
}
|
240
|
-
}
|
241
|
-
|
242
|
-
if (!unquote(import_path).substr(0, 7).compare("http://") ||
|
243
|
-
!unquote(import_path).substr(0, 8).compare("https://") ||
|
244
|
-
!unquote(import_path).substr(0, 2).compare("//"))
|
263
|
+
if (!do_import(lexed, imp, ctx.c_importers, true))
|
245
264
|
{
|
246
|
-
|
265
|
+
// push single file import
|
266
|
+
import_single_file(imp, lexed);
|
267
|
+
}
|
268
|
+
}
|
269
|
+
else if (lex< uri_prefix >()) {
|
270
|
+
Arguments* args = new (ctx.mem) Arguments(pstate);
|
271
|
+
Function_Call* result = new (ctx.mem) Function_Call(pstate, "url", args);
|
272
|
+
if (lex < uri_value >()) { // chunk seems to work too!
|
273
|
+
String* the_url = parse_interpolated_chunk(lexed);
|
274
|
+
*args << new (ctx.mem) Argument(the_url->pstate(), the_url);
|
247
275
|
}
|
248
276
|
else {
|
249
|
-
|
277
|
+
error("malformed URL", pstate);
|
250
278
|
}
|
251
|
-
|
252
|
-
|
253
|
-
else if (peek< uri_prefix >()) {
|
254
|
-
imp->urls().push_back(parse_value());
|
279
|
+
if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
|
280
|
+
imp->urls().push_back(result);
|
255
281
|
}
|
256
282
|
else {
|
257
283
|
if (first) error("@import directive requires a url or quoted path", pstate);
|
258
284
|
else error("expecting another url or quoted path in @import list", pstate);
|
259
285
|
}
|
260
286
|
first = false;
|
261
|
-
} while (
|
287
|
+
} while (lex_css< exactly<','> >());
|
262
288
|
return imp;
|
263
289
|
}
|
264
290
|
|
265
291
|
Definition* Parser::parse_definition()
|
266
292
|
{
|
267
293
|
Definition::Type which_type = Definition::MIXIN;
|
268
|
-
if (lex<
|
269
|
-
else if (lex<
|
294
|
+
if (lex< kwd_mixin >()) which_type = Definition::MIXIN;
|
295
|
+
else if (lex< kwd_function >()) which_type = Definition::FUNCTION;
|
270
296
|
string which_str(lexed);
|
271
297
|
if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
|
272
298
|
string name(Util::normalize_underscores(lexed));
|
@@ -279,22 +305,22 @@ namespace Sass {
|
|
279
305
|
else stack.push_back(function_def);
|
280
306
|
Block* body = parse_block();
|
281
307
|
stack.pop_back();
|
282
|
-
Definition* def = new (ctx.mem) Definition(source_position_of_def, name, params, body, which_type);
|
308
|
+
Definition* def = new (ctx.mem) Definition(source_position_of_def, name, params, body, &ctx, which_type);
|
283
309
|
return def;
|
284
310
|
}
|
285
311
|
|
286
312
|
Parameters* Parser::parse_parameters()
|
287
313
|
{
|
288
|
-
string name(lexed);
|
314
|
+
string name(lexed);
|
315
|
+
Position position = after_token;
|
289
316
|
Parameters* params = new (ctx.mem) Parameters(pstate);
|
290
|
-
if (
|
317
|
+
if (lex_css< exactly<'('> >()) {
|
291
318
|
// if there's anything there at all
|
292
|
-
if (!
|
319
|
+
if (!peek_css< exactly<')'> >()) {
|
293
320
|
do (*params) << parse_parameter();
|
294
|
-
while (
|
321
|
+
while (lex_css< exactly<','> >());
|
295
322
|
}
|
296
|
-
|
297
|
-
if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, pstate);
|
323
|
+
if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
|
298
324
|
}
|
299
325
|
return params;
|
300
326
|
}
|
@@ -322,7 +348,7 @@ namespace Sass {
|
|
322
348
|
|
323
349
|
Mixin_Call* Parser::parse_mixin_call()
|
324
350
|
{
|
325
|
-
lex<
|
351
|
+
lex< kwd_include >() /* || lex< exactly<'+'> >() */;
|
326
352
|
if (!lex< identifier >()) error("invalid name in @include directive", pstate);
|
327
353
|
ParserState source_position_of_call = pstate;
|
328
354
|
string name(Util::normalize_underscores(lexed));
|
@@ -335,34 +361,36 @@ namespace Sass {
|
|
335
361
|
return the_call;
|
336
362
|
}
|
337
363
|
|
338
|
-
Arguments* Parser::parse_arguments()
|
364
|
+
Arguments* Parser::parse_arguments(bool has_url)
|
339
365
|
{
|
340
366
|
string name(lexed);
|
367
|
+
Position position = after_token;
|
341
368
|
Arguments* args = new (ctx.mem) Arguments(pstate);
|
342
|
-
|
343
|
-
if (lex< exactly<'('> >()) {
|
369
|
+
if (lex_css< exactly<'('> >()) {
|
344
370
|
// if there's anything there at all
|
345
|
-
if (!
|
346
|
-
do (*args) << parse_argument();
|
347
|
-
while (
|
371
|
+
if (!peek_css< exactly<')'> >()) {
|
372
|
+
do (*args) << parse_argument(has_url);
|
373
|
+
while (lex_css< exactly<','> >());
|
348
374
|
}
|
349
|
-
|
350
|
-
if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, pstate);
|
375
|
+
if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
|
351
376
|
}
|
352
|
-
|
353
377
|
return args;
|
354
378
|
}
|
355
379
|
|
356
|
-
Argument* Parser::parse_argument()
|
380
|
+
Argument* Parser::parse_argument(bool has_url)
|
357
381
|
{
|
382
|
+
|
358
383
|
Argument* arg;
|
359
|
-
|
360
|
-
if (
|
361
|
-
|
384
|
+
// some urls can look like line comments (parse literally - chunk would not work)
|
385
|
+
if (has_url && lex< sequence < uri_value, lookahead < loosely<')'> > > >(false)) {
|
386
|
+
String* the_url = parse_interpolated_chunk(lexed);
|
387
|
+
arg = new (ctx.mem) Argument(the_url->pstate(), the_url);
|
388
|
+
}
|
389
|
+
else if (peek_css< sequence < variable, optional_css_comments, exactly<':'> > >()) {
|
390
|
+
lex_css< variable >();
|
362
391
|
string name(Util::normalize_underscores(lexed));
|
363
392
|
ParserState p = pstate;
|
364
|
-
|
365
|
-
lex< exactly<':'> >();
|
393
|
+
lex_css< exactly<':'> >();
|
366
394
|
Expression* val = parse_space_list();
|
367
395
|
val->is_delayed(false);
|
368
396
|
arg = new (ctx.mem) Argument(p, val, name);
|
@@ -372,7 +400,7 @@ namespace Sass {
|
|
372
400
|
bool is_keyword = false;
|
373
401
|
Expression* val = parse_space_list();
|
374
402
|
val->is_delayed(false);
|
375
|
-
if (
|
403
|
+
if (lex_css< exactly< ellipsis > >()) {
|
376
404
|
if (val->concrete_type() == Expression::MAP) is_keyword = true;
|
377
405
|
else is_arglist = true;
|
378
406
|
}
|
@@ -389,13 +417,13 @@ namespace Sass {
|
|
389
417
|
if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
|
390
418
|
Expression* val = parse_list();
|
391
419
|
val->is_delayed(false);
|
392
|
-
bool
|
420
|
+
bool is_default = false;
|
393
421
|
bool is_global = false;
|
394
422
|
while (peek< default_flag >() || peek< global_flag >()) {
|
395
|
-
|
423
|
+
is_default = lex< default_flag >() || is_default;
|
396
424
|
is_global = lex< global_flag >() || is_global;
|
397
425
|
}
|
398
|
-
Assignment* var = new (ctx.mem) Assignment(var_source_position, name, val,
|
426
|
+
Assignment* var = new (ctx.mem) Assignment(var_source_position, name, val, is_default, is_global);
|
399
427
|
return var;
|
400
428
|
}
|
401
429
|
|
@@ -432,8 +460,9 @@ namespace Sass {
|
|
432
460
|
sel = parse_selector_group();
|
433
461
|
}
|
434
462
|
bool old_in_at_root = in_at_root;
|
435
|
-
in_at_root = false;
|
436
463
|
ParserState r_source_position = pstate;
|
464
|
+
lex < css_comments >();
|
465
|
+
in_at_root = false;
|
437
466
|
if (!peek< exactly<'{'> >()) error("expected a '{' after the selector", pstate);
|
438
467
|
Block* block = parse_block();
|
439
468
|
in_at_root = old_in_at_root;
|
@@ -477,16 +506,18 @@ namespace Sass {
|
|
477
506
|
{
|
478
507
|
bool reloop = true;
|
479
508
|
To_String to_string(&ctx);
|
480
|
-
lex<
|
509
|
+
lex< css_whitespace >();
|
481
510
|
Selector_List* group = new (ctx.mem) Selector_List(pstate);
|
482
511
|
group->media_block(last_media_block);
|
483
512
|
group->last_block(block_stack.back());
|
484
513
|
do {
|
485
514
|
reloop = false;
|
486
|
-
if (peek<
|
487
|
-
|
488
|
-
|
489
|
-
|
515
|
+
if (peek< alternatives <
|
516
|
+
exactly<'{'>,
|
517
|
+
exactly<'}'>,
|
518
|
+
exactly<')'>,
|
519
|
+
exactly<';'>
|
520
|
+
> >())
|
490
521
|
break; // in case there are superfluous commas at the end
|
491
522
|
Complex_Selector* comb = parse_selector_combination();
|
492
523
|
if (!comb->has_reference() && !in_at_root) {
|
@@ -508,10 +539,10 @@ namespace Sass {
|
|
508
539
|
}
|
509
540
|
if (peek_newline()) ref_wrap->has_line_break(true);
|
510
541
|
}
|
511
|
-
while (
|
542
|
+
while (peek_css< exactly<','> >())
|
512
543
|
{
|
513
544
|
// consume everything up and including the comma speparator
|
514
|
-
reloop = lex< sequence<
|
545
|
+
reloop = lex< sequence < optional_css_comments, exactly<','> > >() != 0;
|
515
546
|
// remember line break (also between some commas)
|
516
547
|
if (peek_newline()) comb->has_line_feed(true);
|
517
548
|
if (comb->tail() && peek_newline()) comb->tail()->has_line_feed(true);
|
@@ -529,15 +560,15 @@ namespace Sass {
|
|
529
560
|
|
530
561
|
Complex_Selector* Parser::parse_selector_combination()
|
531
562
|
{
|
532
|
-
// lex< optional_spaces_and_comments >();
|
533
563
|
Position sel_source_position(-1);
|
534
564
|
Compound_Selector* lhs;
|
535
|
-
if (
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
565
|
+
if (peek_css< alternatives <
|
566
|
+
exactly<'+'>,
|
567
|
+
exactly<'~'>,
|
568
|
+
exactly<'>'>
|
569
|
+
> >())
|
570
|
+
// no selector before the combinator
|
571
|
+
{ lhs = 0; }
|
541
572
|
else {
|
542
573
|
lhs = parse_simple_selector_sequence();
|
543
574
|
sel_source_position = before_token;
|
@@ -552,21 +583,22 @@ namespace Sass {
|
|
552
583
|
bool cpx_lf = peek_newline();
|
553
584
|
|
554
585
|
Complex_Selector* rhs;
|
555
|
-
if (
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
586
|
+
if (peek_css< alternatives <
|
587
|
+
exactly<','>,
|
588
|
+
exactly<')'>,
|
589
|
+
exactly<'{'>,
|
590
|
+
exactly<'}'>,
|
591
|
+
exactly<';'>,
|
592
|
+
optional
|
593
|
+
> >())
|
594
|
+
// no selector after the combinator
|
595
|
+
{ rhs = 0; }
|
564
596
|
else {
|
565
597
|
rhs = parse_selector_combination();
|
566
598
|
sel_source_position = before_token;
|
567
599
|
}
|
568
600
|
if (!sel_source_position.line) sel_source_position = before_token;
|
569
|
-
Complex_Selector* cpx = new (ctx.mem) Complex_Selector(ParserState(path, sel_source_position), cmb, lhs, rhs);
|
601
|
+
Complex_Selector* cpx = new (ctx.mem) Complex_Selector(ParserState(path, source, sel_source_position), cmb, lhs, rhs);
|
570
602
|
cpx->media_block(last_media_block);
|
571
603
|
cpx->last_block(block_stack.back());
|
572
604
|
if (cpx_lf) cpx->has_line_break(cpx_lf);
|
@@ -582,19 +614,19 @@ namespace Sass {
|
|
582
614
|
if (lex< exactly<'&'> >()) {
|
583
615
|
// check if we have a parent selector on the root level block
|
584
616
|
if (block_stack.back() && block_stack.back()->is_root()) {
|
585
|
-
error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
|
617
|
+
//error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
|
586
618
|
}
|
587
619
|
(*seq) << new (ctx.mem) Selector_Reference(pstate);
|
588
620
|
sawsomething = true;
|
589
621
|
// if you see a space after a &, then you're done
|
590
|
-
if(peek< spaces >()) {
|
622
|
+
if(peek< spaces >() || peek< alternatives < spaces, exactly<';'> > >()) {
|
591
623
|
return seq;
|
592
624
|
}
|
593
625
|
}
|
594
|
-
if (sawsomething &&
|
626
|
+
if (sawsomething && lex_css< sequence< negate< functional >, alternatives< identifier_alnums, universal, quoted_string, dimension, percentage, number > > >()) {
|
595
627
|
// saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
|
596
628
|
(*seq) << new (ctx.mem) Type_Selector(pstate, unquote(lexed));
|
597
|
-
} else if (
|
629
|
+
} else if (lex_css< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
|
598
630
|
// if you see a type selector
|
599
631
|
(*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
|
600
632
|
sawsomething = true;
|
@@ -605,14 +637,16 @@ namespace Sass {
|
|
605
637
|
}
|
606
638
|
|
607
639
|
while (!peek< spaces >(position) &&
|
608
|
-
!(
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
640
|
+
!(peek_css < alternatives <
|
641
|
+
exactly<'+'>,
|
642
|
+
exactly<'~'>,
|
643
|
+
exactly<'>'>,
|
644
|
+
exactly<','>,
|
645
|
+
exactly<')'>,
|
646
|
+
exactly<'{'>,
|
647
|
+
exactly<'}'>,
|
648
|
+
exactly<';'>
|
649
|
+
> >(position))) {
|
616
650
|
(*seq) << parse_simple_selector();
|
617
651
|
}
|
618
652
|
return seq;
|
@@ -620,12 +654,16 @@ namespace Sass {
|
|
620
654
|
|
621
655
|
Simple_Selector* Parser::parse_simple_selector()
|
622
656
|
{
|
623
|
-
|
657
|
+
lex < css_comments >();
|
658
|
+
if (lex< alternatives < id_name, class_name > >()) {
|
624
659
|
return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
|
625
660
|
}
|
626
|
-
else if (lex< quoted_string >()
|
661
|
+
else if (lex< quoted_string >()) {
|
627
662
|
return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
|
628
663
|
}
|
664
|
+
else if (lex< alternatives < number, kwd_sel_deep > >()) {
|
665
|
+
return new (ctx.mem) Type_Selector(pstate, lexed);
|
666
|
+
}
|
629
667
|
else if (peek< pseudo_not >()) {
|
630
668
|
return parse_negated_selector();
|
631
669
|
}
|
@@ -675,7 +713,7 @@ namespace Sass {
|
|
675
713
|
lex< sign >();
|
676
714
|
String_Constant* op = new (ctx.mem) String_Quoted(p, lexed);
|
677
715
|
// Binary_Expression::Type op = (lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
|
678
|
-
lex<
|
716
|
+
lex< one_plus < digit > >();
|
679
717
|
String_Constant* constant = new (ctx.mem) String_Quoted(p, lexed);
|
680
718
|
// expr = new (ctx.mem) Binary_Expression(p, op, var_coef, constant);
|
681
719
|
String_Schema* schema = new (ctx.mem) String_Schema(p, 3);
|
@@ -683,19 +721,19 @@ namespace Sass {
|
|
683
721
|
expr = schema;
|
684
722
|
}
|
685
723
|
else if (peek< sequence< optional<sign>,
|
686
|
-
|
724
|
+
zero_plus<digit>,
|
687
725
|
exactly<'n'>,
|
688
|
-
|
726
|
+
optional_css_whitespace,
|
689
727
|
exactly<')'> > >()) {
|
690
728
|
lex< sequence< optional<sign>,
|
691
|
-
|
729
|
+
zero_plus<digit>,
|
692
730
|
exactly<'n'> > >();
|
693
731
|
expr = new (ctx.mem) String_Quoted(p, lexed);
|
694
732
|
}
|
695
|
-
else if (lex< sequence< optional<sign>,
|
733
|
+
else if (lex< sequence< optional<sign>, one_plus < digit > > >()) {
|
696
734
|
expr = new (ctx.mem) String_Quoted(p, lexed);
|
697
735
|
}
|
698
|
-
else if (peek< sequence< identifier,
|
736
|
+
else if (peek< sequence< identifier, optional_css_whitespace, exactly<')'> > >()) {
|
699
737
|
lex< identifier >();
|
700
738
|
expr = new (ctx.mem) String_Quoted(p, lexed);
|
701
739
|
}
|
@@ -726,32 +764,42 @@ namespace Sass {
|
|
726
764
|
|
727
765
|
Attribute_Selector* Parser::parse_attribute_selector()
|
728
766
|
{
|
729
|
-
|
767
|
+
lex_css< exactly<'['> >();
|
730
768
|
ParserState p = pstate;
|
731
|
-
if (!
|
769
|
+
if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector", pstate);
|
732
770
|
string name(lexed);
|
733
|
-
if (
|
734
|
-
if (!
|
735
|
-
|
771
|
+
if (lex_css< exactly<']'> >()) return new (ctx.mem) Attribute_Selector(p, name, "", 0);
|
772
|
+
if (!lex_css< alternatives< exact_match, class_match, dash_match,
|
773
|
+
prefix_match, suffix_match, substring_match > >()) {
|
736
774
|
error("invalid operator in attribute selector for " + name, pstate);
|
737
775
|
}
|
738
776
|
string matcher(lexed);
|
739
777
|
|
740
778
|
String* value = 0;
|
741
|
-
if (
|
779
|
+
if (lex_css< identifier >()) {
|
742
780
|
value = new (ctx.mem) String_Constant(p, lexed);
|
743
781
|
}
|
744
|
-
else if (
|
782
|
+
else if (lex_css< quoted_string >()) {
|
745
783
|
value = parse_interpolated_chunk(lexed, true); // needed!
|
746
784
|
}
|
747
785
|
else {
|
748
786
|
error("expected a string constant or identifier in attribute selector for " + name, pstate);
|
749
787
|
}
|
750
788
|
|
751
|
-
if (!
|
789
|
+
if (!lex_css< exactly<']'> >()) error("unterminated attribute selector for " + name, pstate);
|
752
790
|
return new (ctx.mem) Attribute_Selector(p, name, matcher, value);
|
753
791
|
}
|
754
792
|
|
793
|
+
/* parse block comment and add to block */
|
794
|
+
void Parser::parse_block_comments(Block* block)
|
795
|
+
{
|
796
|
+
while (lex< block_comment >()) {
|
797
|
+
bool is_important = lexed.begin[2] == '!';
|
798
|
+
String* contents = parse_interpolated_chunk(lexed);
|
799
|
+
(*block) << new (ctx.mem) Comment(pstate, contents, is_important);
|
800
|
+
}
|
801
|
+
}
|
802
|
+
|
755
803
|
Block* Parser::parse_block()
|
756
804
|
{
|
757
805
|
lex< exactly<'{'> >();
|
@@ -761,36 +809,21 @@ namespace Sass {
|
|
761
809
|
block_stack.push_back(block);
|
762
810
|
lex< zero_plus < alternatives < space, line_comment > > >();
|
763
811
|
// JMA - ensure that a block containing only block_comments is parsed
|
764
|
-
|
765
|
-
bool is_important = lexed.begin[2] == '!';
|
766
|
-
String* contents = parse_interpolated_chunk(lexed);
|
767
|
-
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
768
|
-
(*block) << comment;
|
769
|
-
}
|
812
|
+
parse_block_comments(block);
|
770
813
|
|
771
814
|
while (!lex< exactly<'}'> >()) {
|
815
|
+
parse_block_comments(block);
|
772
816
|
if (semicolon) {
|
773
817
|
if (!lex< one_plus< exactly<';'> > >()) {
|
774
818
|
error("non-terminal statement or declaration must end with ';'", pstate);
|
775
819
|
}
|
776
820
|
semicolon = false;
|
777
|
-
|
778
|
-
bool is_important = lexed.begin[2] == '!';
|
779
|
-
String* contents = parse_interpolated_chunk(lexed);
|
780
|
-
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
781
|
-
(*block) << comment;
|
782
|
-
}
|
821
|
+
parse_block_comments(block);
|
783
822
|
if (lex< sequence< exactly<'}'>, zero_plus< exactly<';'> > > >()) break;
|
784
823
|
}
|
785
|
-
if (
|
786
|
-
bool is_important = lexed.begin[2] == '!';
|
787
|
-
String* contents = parse_interpolated_chunk(lexed);
|
788
|
-
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
789
|
-
(*block) << comment;
|
790
|
-
}
|
791
|
-
else if (peek< import >(position)) {
|
824
|
+
else if (peek< kwd_import >(position)) {
|
792
825
|
if (stack.back() == mixin_def || stack.back() == function_def) {
|
793
|
-
lex<
|
826
|
+
lex< kwd_import >(); // to adjust the before_token number
|
794
827
|
error("@import directives are not allowed inside mixins and functions", pstate);
|
795
828
|
}
|
796
829
|
Import* imp = parse_import();
|
@@ -809,47 +842,47 @@ namespace Sass {
|
|
809
842
|
else if (lex< line_comment >()) {
|
810
843
|
// throw line comments away
|
811
844
|
}
|
812
|
-
else if (peek<
|
845
|
+
else if (peek< kwd_if_directive >()) {
|
813
846
|
(*block) << parse_if_directive();
|
814
847
|
}
|
815
|
-
else if (peek<
|
848
|
+
else if (peek< kwd_for_directive >()) {
|
816
849
|
(*block) << parse_for_directive();
|
817
850
|
}
|
818
|
-
else if (peek<
|
851
|
+
else if (peek< kwd_each_directive >()) {
|
819
852
|
(*block) << parse_each_directive();
|
820
853
|
}
|
821
|
-
else if (peek <
|
854
|
+
else if (peek < kwd_while_directive >()) {
|
822
855
|
(*block) << parse_while_directive();
|
823
856
|
}
|
824
|
-
else if (lex <
|
857
|
+
else if (lex < kwd_return_directive >()) {
|
825
858
|
(*block) << new (ctx.mem) Return(pstate, parse_list());
|
826
859
|
semicolon = true;
|
827
860
|
}
|
828
|
-
else if (peek<
|
861
|
+
else if (peek< kwd_warn >()) {
|
829
862
|
(*block) << parse_warning();
|
830
863
|
semicolon = true;
|
831
864
|
}
|
832
|
-
else if (peek<
|
865
|
+
else if (peek< kwd_err >()) {
|
833
866
|
(*block) << parse_error();
|
834
867
|
semicolon = true;
|
835
868
|
}
|
836
|
-
else if (peek<
|
869
|
+
else if (peek< kwd_dbg >()) {
|
837
870
|
(*block) << parse_debug();
|
838
871
|
semicolon = true;
|
839
872
|
}
|
840
873
|
else if (stack.back() == function_def) {
|
841
874
|
error("only variable declarations and control directives are allowed inside functions", pstate);
|
842
875
|
}
|
843
|
-
else if (peek<
|
876
|
+
else if (peek< kwd_mixin >() || peek< kwd_function >()) {
|
844
877
|
(*block) << parse_definition();
|
845
878
|
}
|
846
|
-
else if (peek<
|
879
|
+
else if (peek< kwd_include >(position)) {
|
847
880
|
Mixin_Call* the_call = parse_mixin_call();
|
848
881
|
(*block) << the_call;
|
849
882
|
// don't need a semicolon after a content block
|
850
883
|
semicolon = (the_call->block()) ? false : true;
|
851
884
|
}
|
852
|
-
else if (lex<
|
885
|
+
else if (lex< kwd_content >()) {
|
853
886
|
if (stack.back() != mixin_def) {
|
854
887
|
error("@content may only be used within a mixin", pstate);
|
855
888
|
}
|
@@ -862,7 +895,7 @@ namespace Sass {
|
|
862
895
|
semicolon = true;
|
863
896
|
}
|
864
897
|
*/
|
865
|
-
else if (lex<
|
898
|
+
else if (lex< kwd_extend >()) {
|
866
899
|
Selector_Lookahead lookahead = lookahead_for_extension_target(position);
|
867
900
|
if (!lookahead.found) error("invalid selector for @extend", pstate);
|
868
901
|
Selector* target;
|
@@ -871,13 +904,13 @@ namespace Sass {
|
|
871
904
|
(*block) << new (ctx.mem) Extension(pstate, target);
|
872
905
|
semicolon = true;
|
873
906
|
}
|
874
|
-
else if (peek<
|
907
|
+
else if (peek< kwd_media >()) {
|
875
908
|
(*block) << parse_media_block();
|
876
909
|
}
|
877
|
-
else if (peek<
|
910
|
+
else if (peek< kwd_supports >()) {
|
878
911
|
(*block) << parse_feature_block();
|
879
912
|
}
|
880
|
-
else if (peek<
|
913
|
+
else if (peek< kwd_at_root >()) {
|
881
914
|
(*block) << parse_at_root_block();
|
882
915
|
}
|
883
916
|
// ignore the @charset directive for now
|
@@ -923,12 +956,7 @@ namespace Sass {
|
|
923
956
|
}
|
924
957
|
}
|
925
958
|
else lex< one_plus< exactly<';'> > >();
|
926
|
-
|
927
|
-
bool is_important = lexed.begin[2] == '!';
|
928
|
-
String* contents = parse_interpolated_chunk(lexed);
|
929
|
-
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
930
|
-
(*block) << comment;
|
931
|
-
}
|
959
|
+
parse_block_comments(block);
|
932
960
|
}
|
933
961
|
block_stack.pop_back();
|
934
962
|
return block;
|
@@ -942,19 +970,23 @@ namespace Sass {
|
|
942
970
|
else if (lex< sequence< optional< exactly<'*'> >, identifier > >()) {
|
943
971
|
prop = new (ctx.mem) String_Quoted(pstate, lexed);
|
944
972
|
}
|
945
|
-
else if (lex< custom_property_name >()) {
|
946
|
-
prop = new (ctx.mem) String_Quoted(pstate, lexed);
|
947
|
-
}
|
948
973
|
else {
|
949
974
|
error("invalid property name", pstate);
|
950
975
|
}
|
951
|
-
|
952
|
-
if (
|
953
|
-
if (
|
976
|
+
const string property(lexed);
|
977
|
+
if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + property + "\" must be followed by a ':'", pstate);
|
978
|
+
if (peek_css< exactly<';'> >()) error("style declaration must contain a value", pstate);
|
979
|
+
if (peek_css< static_value >()) {
|
954
980
|
return new (ctx.mem) Declaration(prop->pstate(), prop, parse_static_value()/*, lex<important>()*/);
|
955
981
|
}
|
956
982
|
else {
|
957
|
-
|
983
|
+
Expression* list_ex = parse_list();
|
984
|
+
if (List* list = dynamic_cast<List*>(list_ex)) {
|
985
|
+
if (list->length() == 0 && !peek< exactly <'{'> >()) {
|
986
|
+
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
987
|
+
}
|
988
|
+
}
|
989
|
+
return new (ctx.mem) Declaration(prop->pstate(), prop, list_ex/*, lex<important>()*/);
|
958
990
|
}
|
959
991
|
}
|
960
992
|
|
@@ -990,10 +1022,10 @@ namespace Sass {
|
|
990
1022
|
Map* map = new (ctx.mem) Map(pstate, 1);
|
991
1023
|
(*map) << make_pair(key, value);
|
992
1024
|
|
993
|
-
while (
|
1025
|
+
while (lex_css< exactly<','> >())
|
994
1026
|
{
|
995
1027
|
// allow trailing commas - #495
|
996
|
-
if (
|
1028
|
+
if (peek_css< exactly<')'> >(position))
|
997
1029
|
{ break; }
|
998
1030
|
|
999
1031
|
Expression* key = parse_list();
|
@@ -1019,32 +1051,35 @@ namespace Sass {
|
|
1019
1051
|
|
1020
1052
|
Expression* Parser::parse_comma_list()
|
1021
1053
|
{
|
1022
|
-
if (
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1054
|
+
if (peek_css< alternatives <
|
1055
|
+
// exactly<'!'>,
|
1056
|
+
// exactly<':'>,
|
1057
|
+
exactly<';'>,
|
1058
|
+
exactly<'}'>,
|
1059
|
+
exactly<'{'>,
|
1060
|
+
exactly<')'>,
|
1061
|
+
exactly<ellipsis>
|
1062
|
+
> >(position))
|
1029
1063
|
{ return new (ctx.mem) List(pstate, 0); }
|
1030
1064
|
Expression* list1 = parse_space_list();
|
1031
1065
|
// if it's a singleton, return it directly; don't wrap it
|
1032
|
-
if (!
|
1066
|
+
if (!peek_css< exactly<','> >(position)) return list1;
|
1033
1067
|
|
1034
1068
|
List* comma_list = new (ctx.mem) List(pstate, 2, List::COMMA);
|
1035
1069
|
(*comma_list) << list1;
|
1036
1070
|
|
1037
|
-
while (
|
1071
|
+
while (lex_css< exactly<','> >())
|
1038
1072
|
{
|
1039
|
-
if (
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1073
|
+
if (peek_css< alternatives <
|
1074
|
+
// exactly<'!'>,
|
1075
|
+
exactly<';'>,
|
1076
|
+
exactly<'}'>,
|
1077
|
+
exactly<'{'>,
|
1078
|
+
exactly<')'>,
|
1079
|
+
exactly<':'>,
|
1080
|
+
exactly<ellipsis>
|
1081
|
+
> >(position)
|
1082
|
+
) { break; }
|
1048
1083
|
Expression* list = parse_space_list();
|
1049
1084
|
(*comma_list) << list;
|
1050
1085
|
}
|
@@ -1056,32 +1091,36 @@ namespace Sass {
|
|
1056
1091
|
{
|
1057
1092
|
Expression* disj1 = parse_disjunction();
|
1058
1093
|
// if it's a singleton, return it directly; don't wrap it
|
1059
|
-
if (
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1094
|
+
if (peek_css< alternatives <
|
1095
|
+
// exactly<'!'>,
|
1096
|
+
exactly<';'>,
|
1097
|
+
exactly<'}'>,
|
1098
|
+
exactly<'{'>,
|
1099
|
+
exactly<')'>,
|
1100
|
+
exactly<','>,
|
1101
|
+
exactly<':'>,
|
1102
|
+
exactly<ellipsis>,
|
1103
|
+
default_flag,
|
1104
|
+
global_flag
|
1105
|
+
> >(position)
|
1106
|
+
) { return disj1; }
|
1070
1107
|
|
1071
1108
|
List* space_list = new (ctx.mem) List(pstate, 2, List::SPACE);
|
1072
1109
|
(*space_list) << disj1;
|
1073
1110
|
|
1074
|
-
while (!(
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1111
|
+
while (!(peek_css< alternatives <
|
1112
|
+
// exactly<'!'>,
|
1113
|
+
exactly<';'>,
|
1114
|
+
exactly<'}'>,
|
1115
|
+
exactly<'{'>,
|
1116
|
+
exactly<')'>,
|
1117
|
+
exactly<','>,
|
1118
|
+
exactly<':'>,
|
1119
|
+
exactly<ellipsis>,
|
1120
|
+
default_flag,
|
1121
|
+
global_flag
|
1122
|
+
> >(position))
|
1123
|
+
) {
|
1085
1124
|
(*space_list) << parse_disjunction();
|
1086
1125
|
}
|
1087
1126
|
|
@@ -1092,10 +1131,10 @@ namespace Sass {
|
|
1092
1131
|
{
|
1093
1132
|
Expression* conj1 = parse_conjunction();
|
1094
1133
|
// if it's a singleton, return it directly; don't wrap it
|
1095
|
-
if (!
|
1134
|
+
if (!peek_css< kwd_or >()) return conj1;
|
1096
1135
|
|
1097
1136
|
vector<Expression*> operands;
|
1098
|
-
while (
|
1137
|
+
while (lex_css< kwd_or >())
|
1099
1138
|
operands.push_back(parse_conjunction());
|
1100
1139
|
|
1101
1140
|
return fold_operands(conj1, operands, Binary_Expression::OR);
|
@@ -1105,10 +1144,10 @@ namespace Sass {
|
|
1105
1144
|
{
|
1106
1145
|
Expression* rel1 = parse_relation();
|
1107
1146
|
// if it's a singleton, return it directly; don't wrap it
|
1108
|
-
if (!
|
1147
|
+
if (!peek_css< kwd_and >()) return rel1;
|
1109
1148
|
|
1110
1149
|
vector<Expression*> operands;
|
1111
|
-
while (
|
1150
|
+
while (lex_css< kwd_and >())
|
1112
1151
|
operands.push_back(parse_relation());
|
1113
1152
|
|
1114
1153
|
return fold_operands(rel1, operands, Binary_Expression::AND);
|
@@ -1118,21 +1157,23 @@ namespace Sass {
|
|
1118
1157
|
{
|
1119
1158
|
Expression* expr1 = parse_expression();
|
1120
1159
|
// if it's a singleton, return it directly; don't wrap it
|
1121
|
-
if (!(peek<
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1160
|
+
if (!(peek< alternatives <
|
1161
|
+
kwd_eq,
|
1162
|
+
kwd_neq,
|
1163
|
+
kwd_gte,
|
1164
|
+
kwd_gt,
|
1165
|
+
kwd_lte,
|
1166
|
+
kwd_lt
|
1167
|
+
> >(position)))
|
1127
1168
|
{ return expr1; }
|
1128
1169
|
|
1129
1170
|
Binary_Expression::Type op
|
1130
|
-
= lex<
|
1131
|
-
: lex<
|
1132
|
-
: lex<
|
1133
|
-
: lex<
|
1134
|
-
: lex<
|
1135
|
-
: lex<
|
1171
|
+
= lex<kwd_eq>() ? Binary_Expression::EQ
|
1172
|
+
: lex<kwd_neq>() ? Binary_Expression::NEQ
|
1173
|
+
: lex<kwd_gte>() ? Binary_Expression::GTE
|
1174
|
+
: lex<kwd_lte>() ? Binary_Expression::LTE
|
1175
|
+
: lex<kwd_gt>() ? Binary_Expression::GT
|
1176
|
+
: lex<kwd_lt>() ? Binary_Expression::LT
|
1136
1177
|
: Binary_Expression::LT; // whatever
|
1137
1178
|
|
1138
1179
|
Expression* expr2 = parse_expression();
|
@@ -1152,7 +1193,7 @@ namespace Sass {
|
|
1152
1193
|
|
1153
1194
|
vector<Expression*> operands;
|
1154
1195
|
vector<Binary_Expression::Type> operators;
|
1155
|
-
while (lex< exactly<'+'> >() || lex< sequence< negate<
|
1196
|
+
while (lex< exactly<'+'> >() || lex< sequence< negate< digit >, exactly<'-'> > >()) {
|
1156
1197
|
operators.push_back(lexed.to_string() == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
|
1157
1198
|
operands.push_back(parse_term());
|
1158
1199
|
}
|
@@ -1162,38 +1203,35 @@ namespace Sass {
|
|
1162
1203
|
|
1163
1204
|
Expression* Parser::parse_term()
|
1164
1205
|
{
|
1165
|
-
Expression*
|
1166
|
-
|
1206
|
+
Expression* factor = parse_factor();
|
1167
1207
|
// Special case: Ruby sass never tries to modulo if the lhs contains an interpolant
|
1168
|
-
if (
|
1169
|
-
String_Schema* ss = dynamic_cast<String_Schema*>(
|
1170
|
-
if (ss && ss->has_interpolants()) return
|
1208
|
+
if (peek_css< exactly<'%'> >(position) && factor->concrete_type() == Expression::STRING) {
|
1209
|
+
String_Schema* ss = dynamic_cast<String_Schema*>(factor);
|
1210
|
+
if (ss && ss->has_interpolants()) return factor;
|
1171
1211
|
}
|
1172
|
-
|
1173
1212
|
// if it's a singleton, return it directly; don't wrap it
|
1174
|
-
if (!
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
else operators.push_back(Binary_Expression::MOD);
|
1213
|
+
if (!peek< class_char< static_ops > >(position)) return factor;
|
1214
|
+
// parse more factors and operators
|
1215
|
+
vector<Expression*> operands; // factors
|
1216
|
+
vector<Binary_Expression::Type> operators; // ops
|
1217
|
+
while (lex_css< class_char< static_ops > >()) {
|
1218
|
+
switch(*lexed.begin) {
|
1219
|
+
case '*': operators.push_back(Binary_Expression::MUL); break;
|
1220
|
+
case '/': operators.push_back(Binary_Expression::DIV); break;
|
1221
|
+
case '%': operators.push_back(Binary_Expression::MOD); break;
|
1222
|
+
default: throw runtime_error("unknown static op parsed"); break;
|
1223
|
+
}
|
1186
1224
|
operands.push_back(parse_factor());
|
1187
1225
|
}
|
1188
|
-
|
1189
|
-
return fold_operands(
|
1226
|
+
// operands and operators to binary expression
|
1227
|
+
return fold_operands(factor, operands, operators);
|
1190
1228
|
}
|
1191
1229
|
|
1192
1230
|
Expression* Parser::parse_factor()
|
1193
1231
|
{
|
1194
|
-
if (
|
1232
|
+
if (lex_css< exactly<'('> >()) {
|
1195
1233
|
Expression* value = parse_map();
|
1196
|
-
if (!
|
1234
|
+
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
|
1197
1235
|
value->is_delayed(false);
|
1198
1236
|
// make sure wrapped lists and division expressions are non-delayed within parentheses
|
1199
1237
|
if (value->concrete_type() == Expression::LIST) {
|
@@ -1224,19 +1262,19 @@ namespace Sass {
|
|
1224
1262
|
else if (peek< sequence< identifier_schema, negate< exactly<'%'> > > >()) {
|
1225
1263
|
return parse_identifier_schema();
|
1226
1264
|
}
|
1227
|
-
else if (peek< functional >()
|
1265
|
+
else if (peek< functional >()) {
|
1228
1266
|
return parse_function_call();
|
1229
1267
|
}
|
1230
|
-
else if (lex< sequence< exactly<'+'>,
|
1268
|
+
else if (lex< sequence< exactly<'+'>, optional_css_whitespace, negate< number > > >()) {
|
1231
1269
|
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::PLUS, parse_factor());
|
1232
1270
|
}
|
1233
|
-
else if (lex< sequence< exactly<'-'>,
|
1271
|
+
else if (lex< sequence< exactly<'-'>, optional_css_whitespace, negate< number> > >()) {
|
1234
1272
|
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_factor());
|
1235
1273
|
}
|
1236
|
-
else if (lex< sequence<
|
1274
|
+
else if (lex< sequence< kwd_not, css_whitespace > >()) {
|
1237
1275
|
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::NOT, parse_factor());
|
1238
1276
|
}
|
1239
|
-
else if (peek < sequence < one_plus < alternatives <
|
1277
|
+
else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
|
1240
1278
|
if (parse_number_prefix()) return parse_value(); // prefix is positive
|
1241
1279
|
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_value());
|
1242
1280
|
}
|
@@ -1247,44 +1285,10 @@ namespace Sass {
|
|
1247
1285
|
|
1248
1286
|
Expression* Parser::parse_value()
|
1249
1287
|
{
|
1250
|
-
|
1251
|
-
if (lex<
|
1252
|
-
|
1253
|
-
|
1254
|
-
const char* here = position;
|
1255
|
-
Position here_p = before_token;
|
1256
|
-
// Try to parse a SassScript expression. If it succeeds and we can munch
|
1257
|
-
// a matching rparen, then that's our url. If we can't munch a matching
|
1258
|
-
// rparen, or if the attempt to parse an expression fails, then try to
|
1259
|
-
// munch a regular CSS url.
|
1260
|
-
try {
|
1261
|
-
// special case -- if there's a comment, treat it as part of a URL
|
1262
|
-
lex<spaces>();
|
1263
|
-
if (peek<line_comment_prefix>() || peek<block_comment_prefix>()) error("comment in URL", pstate); // doesn't really matter what we throw
|
1264
|
-
Expression* expr = parse_list();
|
1265
|
-
if (!lex< exactly<')'> >()) error("dangling expression in URL", pstate); // doesn't really matter what we throw
|
1266
|
-
Argument* arg = new (ctx.mem) Argument(expr->pstate(), expr);
|
1267
|
-
*args << arg;
|
1268
|
-
return result;
|
1269
|
-
}
|
1270
|
-
catch (Sass_Error&) {
|
1271
|
-
// back up so we can try again
|
1272
|
-
position = here;
|
1273
|
-
before_token = here_p;
|
1274
|
-
}
|
1275
|
-
catch (...) { throw; }
|
1276
|
-
lex< spaces >();
|
1277
|
-
if (lex< url >()) {
|
1278
|
-
String* the_url = parse_interpolated_chunk(lexed);
|
1279
|
-
Argument* arg = new (ctx.mem) Argument(the_url->pstate(), the_url);
|
1280
|
-
*args << arg;
|
1281
|
-
}
|
1282
|
-
else {
|
1283
|
-
error("malformed URL", pstate);
|
1284
|
-
}
|
1285
|
-
if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
|
1286
|
-
return result;
|
1287
|
-
}
|
1288
|
+
lex< css_comments >();
|
1289
|
+
if (lex< ampersand >())
|
1290
|
+
{
|
1291
|
+
return new (ctx.mem) Parent_Selector(pstate, parse_selector_group()); }
|
1288
1292
|
|
1289
1293
|
if (lex< important >())
|
1290
1294
|
{ return new (ctx.mem) String_Constant(pstate, "!important"); }
|
@@ -1293,13 +1297,13 @@ namespace Sass {
|
|
1293
1297
|
if ((stop = peek< value_schema >()))
|
1294
1298
|
{ return parse_value_schema(stop); }
|
1295
1299
|
|
1296
|
-
if (lex<
|
1300
|
+
if (lex< kwd_true >())
|
1297
1301
|
{ return new (ctx.mem) Boolean(pstate, true); }
|
1298
1302
|
|
1299
|
-
if (lex<
|
1303
|
+
if (lex< kwd_false >())
|
1300
1304
|
{ return new (ctx.mem) Boolean(pstate, false); }
|
1301
1305
|
|
1302
|
-
if (lex<
|
1306
|
+
if (lex< kwd_null >())
|
1303
1307
|
{ return new (ctx.mem) Null(pstate); }
|
1304
1308
|
|
1305
1309
|
if (lex< identifier >()) {
|
@@ -1366,7 +1370,7 @@ namespace Sass {
|
|
1366
1370
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
|
1367
1371
|
if (j) { --j;
|
1368
1372
|
// parse the interpolant and accumulate it
|
1369
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j
|
1373
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
|
1370
1374
|
interp_node->is_interpolant(true);
|
1371
1375
|
(*schema) << interp_node;
|
1372
1376
|
i = j;
|
@@ -1427,7 +1431,7 @@ namespace Sass {
|
|
1427
1431
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
|
1428
1432
|
if (j) {
|
1429
1433
|
// parse the interpolant and accumulate it
|
1430
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j
|
1434
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
|
1431
1435
|
interp_node->is_interpolant(true);
|
1432
1436
|
(*schema) << interp_node;
|
1433
1437
|
i = j;
|
@@ -1470,7 +1474,7 @@ namespace Sass {
|
|
1470
1474
|
size_t num_items = 0;
|
1471
1475
|
while (position < stop) {
|
1472
1476
|
if (lex< interpolant >()) {
|
1473
|
-
Token insides(Token(lexed.begin + 2, lexed.end - 1
|
1477
|
+
Token insides(Token(lexed.begin + 2, lexed.end - 1));
|
1474
1478
|
Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
|
1475
1479
|
interp_node->is_interpolant(true);
|
1476
1480
|
(*schema) << interp_node;
|
@@ -1564,7 +1568,7 @@ namespace Sass {
|
|
1564
1568
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
|
1565
1569
|
if (j) {
|
1566
1570
|
// parse the interpolant and accumulate it
|
1567
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j
|
1571
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
|
1568
1572
|
interp_node->is_interpolant(true);
|
1569
1573
|
(*schema) << interp_node;
|
1570
1574
|
schema->has_interpolants(true);
|
@@ -1595,7 +1599,7 @@ namespace Sass {
|
|
1595
1599
|
const char* arg_end = position;
|
1596
1600
|
lex< exactly<')'> >();
|
1597
1601
|
|
1598
|
-
Argument* arg = new (ctx.mem) Argument(arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end
|
1602
|
+
Argument* arg = new (ctx.mem) Argument(arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
|
1599
1603
|
Arguments* args = new (ctx.mem) Arguments(arg_pos);
|
1600
1604
|
*args << arg;
|
1601
1605
|
return new (ctx.mem) Function_Call(call_pos, name, args);
|
@@ -1604,11 +1608,9 @@ namespace Sass {
|
|
1604
1608
|
Function_Call* Parser::parse_function_call()
|
1605
1609
|
{
|
1606
1610
|
lex< identifier >();
|
1607
|
-
string name(
|
1608
|
-
|
1609
|
-
|
1610
|
-
Function_Call* the_call = new (ctx.mem) Function_Call(source_position_of_call, name, parse_arguments());
|
1611
|
-
return the_call;
|
1611
|
+
string name(lexed);
|
1612
|
+
Arguments* args = parse_arguments(name == "url");
|
1613
|
+
return new (ctx.mem) Function_Call(pstate, name, args);
|
1612
1614
|
}
|
1613
1615
|
|
1614
1616
|
Function_Call_Schema* Parser::parse_function_call_schema()
|
@@ -1622,19 +1624,20 @@ namespace Sass {
|
|
1622
1624
|
|
1623
1625
|
If* Parser::parse_if_directive(bool else_if)
|
1624
1626
|
{
|
1625
|
-
lex<
|
1627
|
+
lex< kwd_if_directive >() || (else_if && lex< exactly<if_after_else_kwd> >());
|
1626
1628
|
ParserState if_source_position = pstate;
|
1627
1629
|
Expression* predicate = parse_list();
|
1628
1630
|
predicate->is_delayed(false);
|
1629
1631
|
if (!peek< exactly<'{'> >()) error("expected '{' after the predicate for @if", pstate);
|
1630
1632
|
Block* consequent = parse_block();
|
1631
1633
|
Block* alternative = 0;
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1634
|
+
|
1635
|
+
if (lex< elseif_directive >()) {
|
1636
|
+
alternative = new (ctx.mem) Block(pstate);
|
1637
|
+
(*alternative) << parse_if_directive(true);
|
1638
|
+
}
|
1639
|
+
else if (lex< kwd_else_directive >()) {
|
1640
|
+
if (!peek< exactly<'{'> >()) {
|
1638
1641
|
error("expected '{' after @else", pstate);
|
1639
1642
|
}
|
1640
1643
|
else {
|
@@ -1646,16 +1649,16 @@ namespace Sass {
|
|
1646
1649
|
|
1647
1650
|
For* Parser::parse_for_directive()
|
1648
1651
|
{
|
1649
|
-
lex<
|
1652
|
+
lex< kwd_for_directive >();
|
1650
1653
|
ParserState for_source_position = pstate;
|
1651
1654
|
if (!lex< variable >()) error("@for directive requires an iteration variable", pstate);
|
1652
1655
|
string var(Util::normalize_underscores(lexed));
|
1653
|
-
if (!lex<
|
1656
|
+
if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive", pstate);
|
1654
1657
|
Expression* lower_bound = parse_expression();
|
1655
1658
|
lower_bound->is_delayed(false);
|
1656
1659
|
bool inclusive = false;
|
1657
|
-
if (lex<
|
1658
|
-
else if (lex<
|
1660
|
+
if (lex< kwd_through >()) inclusive = true;
|
1661
|
+
else if (lex< kwd_to >()) inclusive = false;
|
1659
1662
|
else error("expected 'through' or 'to' keyword in @for directive", pstate);
|
1660
1663
|
Expression* upper_bound = parse_expression();
|
1661
1664
|
upper_bound->is_delayed(false);
|
@@ -1666,16 +1669,16 @@ namespace Sass {
|
|
1666
1669
|
|
1667
1670
|
Each* Parser::parse_each_directive()
|
1668
1671
|
{
|
1669
|
-
lex <
|
1672
|
+
lex < kwd_each_directive >();
|
1670
1673
|
ParserState each_source_position = pstate;
|
1671
1674
|
if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
|
1672
1675
|
vector<string> vars;
|
1673
1676
|
vars.push_back(Util::normalize_underscores(lexed));
|
1674
|
-
while (
|
1677
|
+
while (lex< exactly<','> >()) {
|
1675
1678
|
if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
|
1676
1679
|
vars.push_back(Util::normalize_underscores(lexed));
|
1677
1680
|
}
|
1678
|
-
if (!lex<
|
1681
|
+
if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive", pstate);
|
1679
1682
|
Expression* list = parse_list();
|
1680
1683
|
list->is_delayed(false);
|
1681
1684
|
if (list->concrete_type() == Expression::LIST) {
|
@@ -1691,7 +1694,7 @@ namespace Sass {
|
|
1691
1694
|
|
1692
1695
|
While* Parser::parse_while_directive()
|
1693
1696
|
{
|
1694
|
-
lex<
|
1697
|
+
lex< kwd_while_directive >();
|
1695
1698
|
ParserState while_source_position = pstate;
|
1696
1699
|
Expression* predicate = parse_list();
|
1697
1700
|
predicate->is_delayed(false);
|
@@ -1701,7 +1704,7 @@ namespace Sass {
|
|
1701
1704
|
|
1702
1705
|
Media_Block* Parser::parse_media_block()
|
1703
1706
|
{
|
1704
|
-
lex<
|
1707
|
+
lex< kwd_media >();
|
1705
1708
|
ParserState media_source_position = pstate;
|
1706
1709
|
|
1707
1710
|
List* media_queries = parse_media_queries();
|
@@ -1776,7 +1779,7 @@ namespace Sass {
|
|
1776
1779
|
|
1777
1780
|
Feature_Block* Parser::parse_feature_block()
|
1778
1781
|
{
|
1779
|
-
lex<
|
1782
|
+
lex< kwd_supports >();
|
1780
1783
|
ParserState supports_source_position = pstate;
|
1781
1784
|
|
1782
1785
|
Feature_Query* feature_queries = parse_feature_queries();
|
@@ -1805,9 +1808,9 @@ namespace Sass {
|
|
1805
1808
|
|
1806
1809
|
Feature_Query_Condition* Parser::parse_feature_query()
|
1807
1810
|
{
|
1808
|
-
if (peek<
|
1809
|
-
else if (peek<
|
1810
|
-
else if (peek<
|
1811
|
+
if (peek< kwd_not >(position)) return parse_supports_negation();
|
1812
|
+
else if (peek< kwd_and >(position)) return parse_supports_conjunction();
|
1813
|
+
else if (peek< kwd_or >(position)) return parse_supports_disjunction();
|
1811
1814
|
else if (peek< exactly<'('> >(position)) return parse_feature_query_in_parens();
|
1812
1815
|
else return parse_supports_declaration();
|
1813
1816
|
}
|
@@ -1826,7 +1829,7 @@ namespace Sass {
|
|
1826
1829
|
|
1827
1830
|
Feature_Query_Condition* Parser::parse_supports_negation()
|
1828
1831
|
{
|
1829
|
-
lex<
|
1832
|
+
lex< kwd_not >();
|
1830
1833
|
|
1831
1834
|
Feature_Query_Condition* cond = parse_feature_query();
|
1832
1835
|
cond->operand(Feature_Query_Condition::NOT);
|
@@ -1836,7 +1839,7 @@ namespace Sass {
|
|
1836
1839
|
|
1837
1840
|
Feature_Query_Condition* Parser::parse_supports_conjunction()
|
1838
1841
|
{
|
1839
|
-
lex<
|
1842
|
+
lex< kwd_and >();
|
1840
1843
|
|
1841
1844
|
Feature_Query_Condition* cond = parse_feature_query();
|
1842
1845
|
cond->operand(Feature_Query_Condition::AND);
|
@@ -1846,7 +1849,7 @@ namespace Sass {
|
|
1846
1849
|
|
1847
1850
|
Feature_Query_Condition* Parser::parse_supports_disjunction()
|
1848
1851
|
{
|
1849
|
-
lex<
|
1852
|
+
lex< kwd_or >();
|
1850
1853
|
|
1851
1854
|
Feature_Query_Condition* cond = parse_feature_query();
|
1852
1855
|
cond->operand(Feature_Query_Condition::OR);
|
@@ -1866,7 +1869,7 @@ namespace Sass {
|
|
1866
1869
|
|
1867
1870
|
At_Root_Block* Parser::parse_at_root_block()
|
1868
1871
|
{
|
1869
|
-
lex<
|
1872
|
+
lex<kwd_at_root>();
|
1870
1873
|
ParserState at_source_position = pstate;
|
1871
1874
|
Block* body = 0;
|
1872
1875
|
At_Root_Expression* expr = 0;
|
@@ -1895,11 +1898,8 @@ namespace Sass {
|
|
1895
1898
|
lex< exactly<'('> >();
|
1896
1899
|
if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
|
1897
1900
|
|
1898
|
-
if (!peek< alternatives<
|
1899
|
-
|
1900
|
-
const char* p = peek< until<')'> >(i);
|
1901
|
-
Token* t = new Token(i, p, Position(0, 0));
|
1902
|
-
error("Invalid CSS after \"(\": expected \"with\" or \"without\", was \""+t->to_string()+"\"", pstate);
|
1901
|
+
if (!peek< alternatives< kwd_with_directive, kwd_without_directive > >()) {
|
1902
|
+
css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
|
1903
1903
|
}
|
1904
1904
|
|
1905
1905
|
Declaration* declaration = parse_declaration();
|
@@ -1945,19 +1945,19 @@ namespace Sass {
|
|
1945
1945
|
|
1946
1946
|
Warning* Parser::parse_warning()
|
1947
1947
|
{
|
1948
|
-
lex<
|
1948
|
+
lex< kwd_warn >();
|
1949
1949
|
return new (ctx.mem) Warning(pstate, parse_list());
|
1950
1950
|
}
|
1951
1951
|
|
1952
1952
|
Error* Parser::parse_error()
|
1953
1953
|
{
|
1954
|
-
lex<
|
1954
|
+
lex< kwd_err >();
|
1955
1955
|
return new (ctx.mem) Error(pstate, parse_list());
|
1956
1956
|
}
|
1957
1957
|
|
1958
1958
|
Debug* Parser::parse_debug()
|
1959
1959
|
{
|
1960
|
-
lex<
|
1960
|
+
lex< kwd_dbg >();
|
1961
1961
|
return new (ctx.mem) Debug(pstate, parse_list());
|
1962
1962
|
}
|
1963
1963
|
|
@@ -1977,8 +1977,9 @@ namespace Sass {
|
|
1977
1977
|
(q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
|
1978
1978
|
(q = peek< percentage >(p)) ||
|
1979
1979
|
(q = peek< dimension >(p)) ||
|
1980
|
-
(q = peek< quoted_string >(p))
|
1980
|
+
(q = peek< quoted_string >(p)) ||
|
1981
1981
|
(q = peek< exactly<'*'> >(p)) ||
|
1982
|
+
(q = peek< exactly<sel_deep_kwd> >(p)) ||
|
1982
1983
|
(q = peek< exactly<'('> >(p)) ||
|
1983
1984
|
(q = peek< exactly<')'> >(p)) ||
|
1984
1985
|
(q = peek< exactly<'['> >(p)) ||
|
@@ -1989,14 +1990,15 @@ namespace Sass {
|
|
1989
1990
|
(q = peek< exactly<','> >(p)) ||
|
1990
1991
|
(saw_stuff && (q = peek< exactly<'-'> >(p))) ||
|
1991
1992
|
(q = peek< binomial >(p)) ||
|
1993
|
+
(q = peek< block_comment >(p)) ||
|
1992
1994
|
(q = peek< sequence< optional<sign>,
|
1993
|
-
|
1995
|
+
zero_plus<digit>,
|
1994
1996
|
exactly<'n'> > >(p)) ||
|
1995
1997
|
(q = peek< sequence< optional<sign>,
|
1996
|
-
|
1998
|
+
one_plus<digit> > >(p)) ||
|
1997
1999
|
(q = peek< number >(p)) ||
|
1998
2000
|
(q = peek< sequence< exactly<'&'>,
|
1999
|
-
|
2001
|
+
identifier_alnums > >(p)) ||
|
2000
2002
|
(q = peek< exactly<'&'> >(p)) ||
|
2001
2003
|
(q = peek< exactly<'%'> >(p)) ||
|
2002
2004
|
(q = peek< alternatives<exact_match,
|
@@ -2036,7 +2038,7 @@ namespace Sass {
|
|
2036
2038
|
(q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
|
2037
2039
|
(q = peek< percentage >(p)) ||
|
2038
2040
|
(q = peek< dimension >(p)) ||
|
2039
|
-
(q = peek< quoted_string >(p))
|
2041
|
+
(q = peek< quoted_string >(p)) ||
|
2040
2042
|
(q = peek< exactly<'*'> >(p)) ||
|
2041
2043
|
(q = peek< exactly<'('> >(p)) ||
|
2042
2044
|
(q = peek< exactly<')'> >(p)) ||
|
@@ -2048,14 +2050,15 @@ namespace Sass {
|
|
2048
2050
|
(q = peek< exactly<','> >(p)) ||
|
2049
2051
|
(saw_stuff && (q = peek< exactly<'-'> >(p))) ||
|
2050
2052
|
(q = peek< binomial >(p)) ||
|
2053
|
+
(q = peek< block_comment >(p)) ||
|
2051
2054
|
(q = peek< sequence< optional<sign>,
|
2052
|
-
|
2055
|
+
zero_plus<digit>,
|
2053
2056
|
exactly<'n'> > >(p)) ||
|
2054
2057
|
(q = peek< sequence< optional<sign>,
|
2055
|
-
|
2058
|
+
one_plus<digit> > >(p)) ||
|
2056
2059
|
(q = peek< number >(p)) ||
|
2057
2060
|
(q = peek< sequence< exactly<'&'>,
|
2058
|
-
|
2061
|
+
identifier_alnums > >(p)) ||
|
2059
2062
|
(q = peek< exactly<'&'> >(p)) ||
|
2060
2063
|
(q = peek< exactly<'%'> >(p)) ||
|
2061
2064
|
(q = peek< alternatives<exact_match,
|
@@ -2184,7 +2187,42 @@ namespace Sass {
|
|
2184
2187
|
|
2185
2188
|
void Parser::error(string msg, Position pos)
|
2186
2189
|
{
|
2187
|
-
throw Sass_Error(Sass_Error::syntax, ParserState(path, pos.line ? pos : before_token, Offset(0, 0)), msg);
|
2190
|
+
throw Sass_Error(Sass_Error::syntax, ParserState(path, source, pos.line ? pos : before_token, Offset(0, 0)), msg);
|
2191
|
+
}
|
2192
|
+
|
2193
|
+
// print a css parsing error with actual context information from parsed source
|
2194
|
+
void Parser::css_error(const string& msg, const string& prefix, const string& middle)
|
2195
|
+
{
|
2196
|
+
int max_len = 14;
|
2197
|
+
const char* pos = peek < optional_spaces >();
|
2198
|
+
bool ellipsis_left = false;
|
2199
|
+
const char* pos_left(pos);
|
2200
|
+
while (*pos_left && pos_left >= source) {
|
2201
|
+
if (pos - pos_left > max_len) {
|
2202
|
+
ellipsis_left = true;
|
2203
|
+
break;
|
2204
|
+
}
|
2205
|
+
if (*pos_left == '\r') break;
|
2206
|
+
if (*pos_left == '\n') break;
|
2207
|
+
-- pos_left;
|
2208
|
+
}
|
2209
|
+
bool ellipsis_right = false;
|
2210
|
+
const char* pos_right(pos);
|
2211
|
+
while (*pos_right && pos_right <= end) {
|
2212
|
+
if (pos_right - pos > max_len) {
|
2213
|
+
ellipsis_right = true;
|
2214
|
+
break;
|
2215
|
+
}
|
2216
|
+
if (*pos_right == '\r') break;
|
2217
|
+
if (*pos_right == '\n') break;
|
2218
|
+
++ pos_right;
|
2219
|
+
}
|
2220
|
+
string left(pos_left, pos);
|
2221
|
+
string right(pos, pos_right);
|
2222
|
+
if (ellipsis_left) left = ellipsis + left;
|
2223
|
+
if (ellipsis_right) right = right + ellipsis;
|
2224
|
+
// now pass new message to the more generic error function
|
2225
|
+
error(msg + prefix + quote(left) + middle + quote(right), pstate);
|
2188
2226
|
}
|
2189
2227
|
|
2190
2228
|
}
|