sassc 0.0.9 → 0.0.10
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/Rakefile +1 -1
- data/ext/libsass/.gitignore +13 -6
- data/ext/libsass/Makefile +42 -26
- data/ext/libsass/Makefile.am +43 -30
- data/ext/libsass/Readme.md +4 -2
- data/ext/libsass/appveyor.yml +10 -14
- data/ext/libsass/ast.cpp +54 -44
- data/ext/libsass/ast.hpp +404 -236
- data/ext/libsass/ast_def_macros.hpp +5 -0
- data/ext/libsass/ast_factory.hpp +6 -3
- data/ext/libsass/ast_fwd_decl.hpp +12 -0
- data/ext/libsass/b64/encode.h +2 -2
- data/ext/libsass/backtrace.hpp +13 -17
- data/ext/libsass/base64vlq.hpp +4 -1
- data/ext/libsass/bind.cpp +12 -15
- data/ext/libsass/bind.hpp +6 -6
- data/ext/libsass/color_names.hpp +4 -1
- data/ext/libsass/configure.ac +7 -21
- data/ext/libsass/constants.cpp +6 -4
- data/ext/libsass/constants.hpp +10 -4
- data/ext/libsass/context.cpp +89 -58
- data/ext/libsass/context.hpp +28 -35
- data/ext/libsass/contextualize.cpp +20 -10
- data/ext/libsass/contextualize.hpp +8 -23
- data/ext/libsass/contrib/libsass.spec +66 -0
- data/ext/libsass/cssize.cpp +547 -0
- data/ext/libsass/cssize.hpp +82 -0
- data/ext/libsass/debug.hpp +3 -3
- data/ext/libsass/debugger.hpp +358 -0
- data/ext/libsass/emitter.cpp +255 -0
- data/ext/libsass/emitter.hpp +83 -0
- data/ext/libsass/environment.hpp +7 -3
- data/ext/libsass/error_handling.cpp +11 -14
- data/ext/libsass/error_handling.hpp +9 -7
- data/ext/libsass/eval.cpp +253 -161
- data/ext/libsass/eval.hpp +13 -13
- data/ext/libsass/expand.cpp +135 -64
- data/ext/libsass/expand.hpp +11 -13
- data/ext/libsass/extend.cpp +66 -20
- data/ext/libsass/extend.hpp +6 -11
- data/ext/libsass/file.cpp +31 -26
- data/ext/libsass/file.hpp +6 -1
- data/ext/libsass/functions.cpp +270 -287
- data/ext/libsass/functions.hpp +8 -11
- data/ext/libsass/inspect.cpp +385 -255
- data/ext/libsass/inspect.hpp +15 -26
- data/ext/libsass/kwd_arg_macros.hpp +5 -0
- data/ext/libsass/mapping.hpp +4 -3
- data/ext/libsass/memory_manager.hpp +5 -2
- data/ext/libsass/node.cpp +50 -50
- data/ext/libsass/node.hpp +26 -27
- data/ext/libsass/operation.hpp +15 -4
- data/ext/libsass/output.cpp +401 -0
- data/ext/libsass/output.hpp +56 -0
- data/ext/libsass/parser.cpp +573 -399
- data/ext/libsass/parser.hpp +122 -88
- data/ext/libsass/paths.hpp +7 -2
- data/ext/libsass/plugins.cpp +155 -0
- data/ext/libsass/plugins.hpp +56 -0
- data/ext/libsass/position.cpp +128 -0
- data/ext/libsass/position.hpp +108 -11
- data/ext/libsass/prelexer.cpp +184 -110
- data/ext/libsass/prelexer.hpp +131 -24
- data/ext/libsass/remove_placeholders.cpp +1 -1
- data/ext/libsass/remove_placeholders.hpp +6 -6
- data/ext/libsass/sass.cpp +3 -3
- data/ext/libsass/sass.h +12 -4
- data/ext/libsass/sass2scss.cpp +3 -2
- data/ext/libsass/sass2scss.h +5 -0
- data/ext/libsass/sass_context.cpp +136 -37
- data/ext/libsass/sass_context.h +19 -10
- data/ext/libsass/sass_functions.cpp +29 -2
- data/ext/libsass/sass_functions.h +8 -2
- data/ext/libsass/sass_interface.cpp +32 -23
- data/ext/libsass/sass_interface.h +9 -4
- data/ext/libsass/sass_util.cpp +19 -23
- data/ext/libsass/sass_util.hpp +28 -27
- data/ext/libsass/sass_values.cpp +6 -4
- data/ext/libsass/sass_values.h +3 -3
- data/ext/libsass/script/ci-build-libsass +13 -1
- data/ext/libsass/script/ci-report-coverage +2 -1
- data/ext/libsass/source_map.cpp +79 -28
- data/ext/libsass/source_map.hpp +35 -16
- data/ext/libsass/subset_map.hpp +6 -4
- data/ext/libsass/to_c.hpp +4 -4
- data/ext/libsass/to_string.cpp +13 -8
- data/ext/libsass/to_string.hpp +6 -4
- data/ext/libsass/units.cpp +2 -1
- data/ext/libsass/units.hpp +6 -1
- data/ext/libsass/utf8_string.cpp +0 -5
- data/ext/libsass/utf8_string.hpp +3 -2
- data/ext/libsass/util.cpp +461 -49
- data/ext/libsass/util.hpp +34 -13
- data/ext/libsass/version.sh +10 -0
- data/ext/libsass/win/libsass.filters +20 -11
- data/ext/libsass/win/libsass.vcxproj +11 -8
- data/lib/sassc/importer.rb +1 -8
- data/lib/sassc/native.rb +7 -0
- data/lib/sassc/native/native_context_api.rb +5 -5
- data/lib/sassc/version.rb +1 -1
- data/test/native_test.rb +1 -1
- metadata +14 -10
- data/ext/libsass/copy_c_str.cpp +0 -13
- data/ext/libsass/copy_c_str.hpp +0 -5
- data/ext/libsass/output_compressed.cpp +0 -401
- data/ext/libsass/output_compressed.hpp +0 -95
- data/ext/libsass/output_nested.cpp +0 -364
- data/ext/libsass/output_nested.hpp +0 -108
- data/ext/libsass/test-driver +0 -127
- data/ext/libsass/token.hpp +0 -32
@@ -0,0 +1,56 @@
|
|
1
|
+
#ifndef SASS_OUTPUT_H
|
2
|
+
#define SASS_OUTPUT_H
|
3
|
+
|
4
|
+
#include <string>
|
5
|
+
#include <vector>
|
6
|
+
|
7
|
+
#include "util.hpp"
|
8
|
+
#include "inspect.hpp"
|
9
|
+
#include "operation.hpp"
|
10
|
+
|
11
|
+
namespace Sass {
|
12
|
+
class Context;
|
13
|
+
using namespace std;
|
14
|
+
|
15
|
+
// Refactor to make it generic to find linefeed (look behind)
|
16
|
+
inline bool ends_with(std::string const & value, std::string const & ending)
|
17
|
+
{
|
18
|
+
if (ending.size() > value.size()) return false;
|
19
|
+
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
|
20
|
+
}
|
21
|
+
|
22
|
+
class Output : public Inspect {
|
23
|
+
protected:
|
24
|
+
using Inspect::operator();
|
25
|
+
|
26
|
+
public:
|
27
|
+
// change to Emitter
|
28
|
+
Output(Context* ctx);
|
29
|
+
virtual ~Output();
|
30
|
+
|
31
|
+
protected:
|
32
|
+
string charset;
|
33
|
+
vector<Import*> top_imports;
|
34
|
+
vector<Comment*> top_comments;
|
35
|
+
|
36
|
+
public:
|
37
|
+
OutputBuffer get_buffer(void);
|
38
|
+
|
39
|
+
virtual void operator()(Ruleset*);
|
40
|
+
// virtual void operator()(Propset*);
|
41
|
+
virtual void operator()(Feature_Block*);
|
42
|
+
virtual void operator()(Media_Block*);
|
43
|
+
virtual void operator()(At_Rule*);
|
44
|
+
virtual void operator()(Keyframe_Rule*);
|
45
|
+
virtual void operator()(Import*);
|
46
|
+
virtual void operator()(Comment*);
|
47
|
+
virtual void operator()(String_Quoted*);
|
48
|
+
virtual void operator()(String_Constant*);
|
49
|
+
|
50
|
+
void fallback_impl(AST_Node* n);
|
51
|
+
|
52
|
+
};
|
53
|
+
|
54
|
+
}
|
55
|
+
|
56
|
+
#endif
|
data/ext/libsass/parser.cpp
CHANGED
@@ -7,11 +7,7 @@
|
|
7
7
|
#include "to_string.hpp"
|
8
8
|
#include "constants.hpp"
|
9
9
|
#include "util.hpp"
|
10
|
-
|
11
|
-
#ifndef SASS_PRELEXER
|
12
10
|
#include "prelexer.hpp"
|
13
|
-
#endif
|
14
|
-
|
15
11
|
#include "sass_functions.h"
|
16
12
|
|
17
13
|
#include <typeinfo>
|
@@ -20,36 +16,60 @@ namespace Sass {
|
|
20
16
|
using namespace std;
|
21
17
|
using namespace Constants;
|
22
18
|
|
23
|
-
Parser Parser::from_c_str(const char* str, Context& ctx,
|
19
|
+
Parser Parser::from_c_str(const char* str, Context& ctx, ParserState pstate)
|
24
20
|
{
|
25
|
-
Parser p(ctx,
|
21
|
+
Parser p(ctx, pstate);
|
26
22
|
p.source = str;
|
27
23
|
p.position = p.source;
|
28
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);
|
29
40
|
return p;
|
30
41
|
}
|
31
42
|
|
32
|
-
|
43
|
+
bool Parser::peek_newline(const char* start)
|
44
|
+
{
|
45
|
+
return peek_linefeed(start ? start : position);
|
46
|
+
}
|
47
|
+
|
48
|
+
Parser Parser::from_token(Token t, Context& ctx, ParserState pstate)
|
33
49
|
{
|
34
|
-
Parser p(ctx,
|
50
|
+
Parser p(ctx, pstate);
|
35
51
|
p.source = t.begin;
|
36
52
|
p.position = p.source;
|
37
53
|
p.end = t.end;
|
38
|
-
|
54
|
+
Block* root = new (ctx.mem) Block(pstate);
|
55
|
+
p.block_stack.push_back(root);
|
56
|
+
root->is_root(true);
|
39
57
|
return p;
|
40
58
|
}
|
41
59
|
|
42
60
|
Block* Parser::parse()
|
43
61
|
{
|
44
|
-
Block* root = new (ctx.mem) Block(
|
62
|
+
Block* root = new (ctx.mem) Block(pstate);
|
63
|
+
block_stack.push_back(root);
|
45
64
|
root->is_root(true);
|
46
65
|
read_bom();
|
47
66
|
lex< optional_spaces >();
|
48
67
|
Selector_Lookahead lookahead_result;
|
49
68
|
while (position < end) {
|
50
69
|
if (lex< block_comment >()) {
|
70
|
+
bool is_important = lexed.begin[2] == '!';
|
51
71
|
String* contents = parse_interpolated_chunk(lexed);
|
52
|
-
Comment* comment = new (ctx.mem) Comment(
|
72
|
+
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
53
73
|
(*root) << comment;
|
54
74
|
}
|
55
75
|
else if (peek< import >()) {
|
@@ -57,25 +77,25 @@ namespace Sass {
|
|
57
77
|
if (!imp->urls().empty()) (*root) << imp;
|
58
78
|
if (!imp->files().empty()) {
|
59
79
|
for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
|
60
|
-
(*root) << new (ctx.mem) Import_Stub(
|
80
|
+
(*root) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
|
61
81
|
}
|
62
82
|
}
|
63
|
-
if (!lex< one_plus< exactly<';'> > >()) error("top-level @import directive must be terminated by ';'");
|
83
|
+
if (!lex< one_plus< exactly<';'> > >()) error("top-level @import directive must be terminated by ';'", pstate);
|
64
84
|
}
|
65
85
|
else if (peek< mixin >() || peek< function >()) {
|
66
86
|
(*root) << parse_definition();
|
67
87
|
}
|
68
88
|
else if (peek< variable >()) {
|
69
89
|
(*root) << parse_assignment();
|
70
|
-
if (!lex< one_plus< exactly<';'> > >()) error("top-level variable binding must be terminated by ';'");
|
90
|
+
if (!lex< one_plus< exactly<';'> > >()) error("top-level variable binding must be terminated by ';'", pstate);
|
71
91
|
}
|
72
|
-
else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
|
92
|
+
/*else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
|
73
93
|
(*root) << parse_propset();
|
74
|
-
}
|
94
|
+
}*/
|
75
95
|
else if (peek< include >() /* || peek< exactly<'+'> >() */) {
|
76
96
|
Mixin_Call* mixin_call = parse_mixin_call();
|
77
97
|
(*root) << mixin_call;
|
78
|
-
if (!mixin_call->block() && !lex< one_plus< exactly<';'> > >()) error("top-level @include directive must be terminated by ';'");
|
98
|
+
if (!mixin_call->block() && !lex< one_plus< exactly<';'> > >()) error("top-level @include directive must be terminated by ';'", pstate);
|
79
99
|
}
|
80
100
|
else if (peek< if_directive >()) {
|
81
101
|
(*root) << parse_if_directive();
|
@@ -92,30 +112,33 @@ namespace Sass {
|
|
92
112
|
else if (peek< media >()) {
|
93
113
|
(*root) << parse_media_block();
|
94
114
|
}
|
115
|
+
else if (peek< at_root >()) {
|
116
|
+
(*root) << parse_at_root_block();
|
117
|
+
}
|
95
118
|
else if (peek< supports >()) {
|
96
119
|
(*root) << parse_feature_block();
|
97
120
|
}
|
98
121
|
else if (peek< warn >()) {
|
99
122
|
(*root) << parse_warning();
|
100
|
-
if (!lex< one_plus< exactly<';'> > >()) error("top-level @warn directive must be terminated by ';'");
|
123
|
+
if (!lex< one_plus< exactly<';'> > >()) error("top-level @warn directive must be terminated by ';'", pstate);
|
101
124
|
}
|
102
125
|
else if (peek< err >()) {
|
103
126
|
(*root) << parse_error();
|
104
|
-
if (!lex< one_plus< exactly<';'> > >()) error("top-level @error directive must be terminated by ';'");
|
127
|
+
if (!lex< one_plus< exactly<';'> > >()) error("top-level @error directive must be terminated by ';'", pstate);
|
105
128
|
}
|
106
129
|
else if (peek< dbg >()) {
|
107
130
|
(*root) << parse_debug();
|
108
|
-
if (!lex< one_plus< exactly<';'> > >()) error("top-level @debug directive must be terminated by ';'");
|
131
|
+
if (!lex< one_plus< exactly<';'> > >()) error("top-level @debug directive must be terminated by ';'", pstate);
|
109
132
|
}
|
110
133
|
// ignore the @charset directive for now
|
111
134
|
else if (lex< exactly< charset_kwd > >()) {
|
112
|
-
lex<
|
135
|
+
lex< quoted_string >();
|
113
136
|
lex< one_plus< exactly<';'> > >();
|
114
137
|
}
|
115
138
|
else if (peek< at_keyword >()) {
|
116
139
|
At_Rule* at_rule = parse_at_rule();
|
117
140
|
(*root) << at_rule;
|
118
|
-
if (!at_rule->block() && !lex< one_plus< exactly<';'> > >()) error("top-level directive must be terminated by ';'");
|
141
|
+
if (!at_rule->block() && !lex< one_plus< exactly<';'> > >()) error("top-level directive must be terminated by ';'", pstate);
|
119
142
|
}
|
120
143
|
else if ((lookahead_result = lookahead_for_selector(position)).found) {
|
121
144
|
(*root) << parse_ruleset(lookahead_result);
|
@@ -124,12 +147,13 @@ namespace Sass {
|
|
124
147
|
lex< one_plus< exactly<';'> > >();
|
125
148
|
}
|
126
149
|
else {
|
127
|
-
lex<
|
150
|
+
lex< optional_spaces_and_comments >();
|
128
151
|
if (position >= end) break;
|
129
|
-
error("invalid top-level expression");
|
152
|
+
error("invalid top-level expression", pstate);
|
130
153
|
}
|
131
154
|
lex< optional_spaces >();
|
132
155
|
}
|
156
|
+
block_stack.pop_back();
|
133
157
|
return root;
|
134
158
|
}
|
135
159
|
|
@@ -143,17 +167,17 @@ namespace Sass {
|
|
143
167
|
}
|
144
168
|
|
145
169
|
if (extension == ".css") {
|
146
|
-
String_Constant* loc = new (ctx.mem) String_Constant(
|
147
|
-
Argument* loc_arg = new (ctx.mem) Argument(
|
148
|
-
Arguments* loc_args = new (ctx.mem) Arguments(
|
170
|
+
String_Constant* loc = new (ctx.mem) String_Constant(pstate, unquote(import_path));
|
171
|
+
Argument* loc_arg = new (ctx.mem) Argument(pstate, loc);
|
172
|
+
Arguments* loc_args = new (ctx.mem) Arguments(pstate);
|
149
173
|
(*loc_args) << loc_arg;
|
150
|
-
Function_Call* new_url = new (ctx.mem) Function_Call(
|
174
|
+
Function_Call* new_url = new (ctx.mem) Function_Call(pstate, "url", loc_args);
|
151
175
|
imp->urls().push_back(new_url);
|
152
176
|
}
|
153
177
|
else {
|
154
178
|
string current_dir = File::dir_name(path);
|
155
179
|
string resolved(ctx.add_file(current_dir, unquoted));
|
156
|
-
if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir);
|
180
|
+
if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir, pstate);
|
157
181
|
imp->files().push_back(resolved);
|
158
182
|
}
|
159
183
|
|
@@ -162,10 +186,11 @@ namespace Sass {
|
|
162
186
|
Import* Parser::parse_import()
|
163
187
|
{
|
164
188
|
lex< import >();
|
165
|
-
Import* imp = new (ctx.mem) Import(
|
189
|
+
Import* imp = new (ctx.mem) Import(pstate);
|
166
190
|
bool first = true;
|
167
191
|
do {
|
168
|
-
|
192
|
+
while (lex< block_comment >());
|
193
|
+
if (lex< quoted_string >()) {
|
169
194
|
string import_path(lexed);
|
170
195
|
|
171
196
|
// struct Sass_Options opt = sass_context_get_options(ctx)
|
@@ -186,9 +211,15 @@ namespace Sass {
|
|
186
211
|
while (*includes) {
|
187
212
|
struct Sass_Import* include = *includes;
|
188
213
|
const char *file = sass_import_get_path(include);
|
189
|
-
char
|
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);
|
190
218
|
// char *srcmap = sass_import_take_srcmap(include);
|
191
|
-
if (
|
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) {
|
192
223
|
if (file) {
|
193
224
|
ctx.add_source(file, inc_path, source);
|
194
225
|
imp->files().push_back(file);
|
@@ -208,15 +239,23 @@ namespace Sass {
|
|
208
239
|
}
|
209
240
|
}
|
210
241
|
|
211
|
-
|
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("//"))
|
245
|
+
{
|
246
|
+
imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
|
247
|
+
}
|
248
|
+
else {
|
249
|
+
add_single_file(imp, import_path);
|
250
|
+
}
|
212
251
|
|
213
252
|
}
|
214
253
|
else if (peek< uri_prefix >()) {
|
215
254
|
imp->urls().push_back(parse_value());
|
216
255
|
}
|
217
256
|
else {
|
218
|
-
if (first) error("@import directive requires a url or quoted path");
|
219
|
-
else error("expecting another url or quoted path in @import list");
|
257
|
+
if (first) error("@import directive requires a url or quoted path", pstate);
|
258
|
+
else error("expecting another url or quoted path in @import list", pstate);
|
220
259
|
}
|
221
260
|
first = false;
|
222
261
|
} while (lex< exactly<','> >());
|
@@ -229,81 +268,86 @@ namespace Sass {
|
|
229
268
|
if (lex< mixin >()) which_type = Definition::MIXIN;
|
230
269
|
else if (lex< function >()) which_type = Definition::FUNCTION;
|
231
270
|
string which_str(lexed);
|
232
|
-
if (!lex< identifier >()) error("invalid name in " + which_str + " definition");
|
271
|
+
if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
|
233
272
|
string name(Util::normalize_underscores(lexed));
|
234
273
|
if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
|
235
|
-
{ error("Invalid function name \"" + name + "\"."); }
|
236
|
-
|
274
|
+
{ error("Invalid function name \"" + name + "\".", pstate); }
|
275
|
+
ParserState source_position_of_def = pstate;
|
237
276
|
Parameters* params = parse_parameters();
|
238
|
-
if (!peek< exactly<'{'> >()) error("body for " + which_str + " " + name + " must begin with a '{'");
|
277
|
+
if (!peek< exactly<'{'> >()) error("body for " + which_str + " " + name + " must begin with a '{'", pstate);
|
239
278
|
if (which_type == Definition::MIXIN) stack.push_back(mixin_def);
|
240
279
|
else stack.push_back(function_def);
|
241
280
|
Block* body = parse_block();
|
242
281
|
stack.pop_back();
|
243
|
-
Definition* def = new (ctx.mem) Definition(
|
282
|
+
Definition* def = new (ctx.mem) Definition(source_position_of_def, name, params, body, which_type);
|
244
283
|
return def;
|
245
284
|
}
|
246
285
|
|
247
286
|
Parameters* Parser::parse_parameters()
|
248
287
|
{
|
249
288
|
string name(lexed); // for the error message
|
250
|
-
Parameters* params = new (ctx.mem) Parameters(
|
289
|
+
Parameters* params = new (ctx.mem) Parameters(pstate);
|
251
290
|
if (lex< exactly<'('> >()) {
|
252
291
|
// if there's anything there at all
|
253
292
|
if (!peek< exactly<')'> >()) {
|
254
293
|
do (*params) << parse_parameter();
|
255
|
-
while (lex< exactly<','> >());
|
294
|
+
while (lex< alternatives < spaces,block_comment, exactly<','> > >());
|
256
295
|
}
|
257
|
-
|
296
|
+
while (lex< alternatives < spaces, block_comment > >()) {};
|
297
|
+
if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, pstate);
|
258
298
|
}
|
259
299
|
return params;
|
260
300
|
}
|
261
301
|
|
262
302
|
Parameter* Parser::parse_parameter()
|
263
303
|
{
|
304
|
+
while (lex< alternatives < spaces, block_comment > >());
|
264
305
|
lex< variable >();
|
265
306
|
string name(Util::normalize_underscores(lexed));
|
266
|
-
|
307
|
+
ParserState pos = pstate;
|
267
308
|
Expression* val = 0;
|
268
309
|
bool is_rest = false;
|
310
|
+
while (lex< alternatives < spaces, block_comment > >());
|
269
311
|
if (lex< exactly<':'> >()) { // there's a default value
|
312
|
+
while (lex< block_comment >());
|
270
313
|
val = parse_space_list();
|
271
314
|
val->is_delayed(false);
|
272
315
|
}
|
273
316
|
else if (lex< exactly< ellipsis > >()) {
|
274
317
|
is_rest = true;
|
275
318
|
}
|
276
|
-
Parameter* p = new (ctx.mem) Parameter(
|
319
|
+
Parameter* p = new (ctx.mem) Parameter(pos, name, val, is_rest);
|
277
320
|
return p;
|
278
321
|
}
|
279
322
|
|
280
323
|
Mixin_Call* Parser::parse_mixin_call()
|
281
324
|
{
|
282
325
|
lex< include >() /* || lex< exactly<'+'> >() */;
|
283
|
-
if (!lex< identifier >()) error("invalid name in @include directive");
|
284
|
-
|
326
|
+
if (!lex< identifier >()) error("invalid name in @include directive", pstate);
|
327
|
+
ParserState source_position_of_call = pstate;
|
285
328
|
string name(Util::normalize_underscores(lexed));
|
286
329
|
Arguments* args = parse_arguments();
|
287
330
|
Block* content = 0;
|
288
331
|
if (peek< exactly<'{'> >()) {
|
289
332
|
content = parse_block();
|
290
333
|
}
|
291
|
-
Mixin_Call* the_call = new (ctx.mem) Mixin_Call(
|
334
|
+
Mixin_Call* the_call = new (ctx.mem) Mixin_Call(source_position_of_call, name, args, content);
|
292
335
|
return the_call;
|
293
336
|
}
|
294
337
|
|
295
338
|
Arguments* Parser::parse_arguments()
|
296
339
|
{
|
297
340
|
string name(lexed);
|
298
|
-
Arguments* args = new (ctx.mem) Arguments(
|
341
|
+
Arguments* args = new (ctx.mem) Arguments(pstate);
|
299
342
|
|
300
343
|
if (lex< exactly<'('> >()) {
|
301
344
|
// if there's anything there at all
|
302
345
|
if (!peek< exactly<')'> >()) {
|
303
346
|
do (*args) << parse_argument();
|
304
|
-
while (lex< exactly<','> >());
|
347
|
+
while (lex< alternatives < block_comment, exactly<','> > >());
|
305
348
|
}
|
306
|
-
|
349
|
+
while (lex< block_comment >());
|
350
|
+
if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, pstate);
|
307
351
|
}
|
308
352
|
|
309
353
|
return args;
|
@@ -312,14 +356,16 @@ namespace Sass {
|
|
312
356
|
Argument* Parser::parse_argument()
|
313
357
|
{
|
314
358
|
Argument* arg;
|
315
|
-
|
359
|
+
while (lex< alternatives < spaces, block_comment > >());
|
360
|
+
if (peek< sequence < variable, zero_plus < alternatives < spaces, line_comment, block_comment > >, exactly<':'> > >()) {
|
316
361
|
lex< variable >();
|
317
362
|
string name(Util::normalize_underscores(lexed));
|
318
|
-
|
363
|
+
ParserState p = pstate;
|
364
|
+
while (lex< alternatives < spaces, block_comment > >()) {};
|
319
365
|
lex< exactly<':'> >();
|
320
366
|
Expression* val = parse_space_list();
|
321
367
|
val->is_delayed(false);
|
322
|
-
arg = new (ctx.mem) Argument(
|
368
|
+
arg = new (ctx.mem) Argument(p, val, name);
|
323
369
|
}
|
324
370
|
else {
|
325
371
|
bool is_arglist = false;
|
@@ -330,7 +376,7 @@ namespace Sass {
|
|
330
376
|
if (val->concrete_type() == Expression::MAP) is_keyword = true;
|
331
377
|
else is_arglist = true;
|
332
378
|
}
|
333
|
-
arg = new (ctx.mem) Argument(
|
379
|
+
arg = new (ctx.mem) Argument(pstate, val, "", is_arglist, is_keyword);
|
334
380
|
}
|
335
381
|
return arg;
|
336
382
|
}
|
@@ -339,8 +385,8 @@ namespace Sass {
|
|
339
385
|
{
|
340
386
|
lex< variable >();
|
341
387
|
string name(Util::normalize_underscores(lexed));
|
342
|
-
|
343
|
-
if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement");
|
388
|
+
ParserState var_source_position = pstate;
|
389
|
+
if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
|
344
390
|
Expression* val = parse_list();
|
345
391
|
val->is_delayed(false);
|
346
392
|
bool is_guarded = false;
|
@@ -349,10 +395,11 @@ namespace Sass {
|
|
349
395
|
is_guarded = lex< default_flag >() || is_guarded;
|
350
396
|
is_global = lex< global_flag >() || is_global;
|
351
397
|
}
|
352
|
-
Assignment* var = new (ctx.mem) Assignment(
|
398
|
+
Assignment* var = new (ctx.mem) Assignment(var_source_position, name, val, is_guarded, is_global);
|
353
399
|
return var;
|
354
400
|
}
|
355
401
|
|
402
|
+
/* not used anymore - remove?
|
356
403
|
Propset* Parser::parse_propset()
|
357
404
|
{
|
358
405
|
String* property_segment;
|
@@ -361,17 +408,19 @@ namespace Sass {
|
|
361
408
|
}
|
362
409
|
else {
|
363
410
|
lex< sequence< optional< exactly<'*'> >, identifier > >();
|
364
|
-
property_segment = new (ctx.mem)
|
411
|
+
property_segment = new (ctx.mem) String_Quoted(pstate, lexed);
|
365
412
|
}
|
366
|
-
Propset* propset = new (ctx.mem) Propset(
|
413
|
+
Propset* propset = new (ctx.mem) Propset(pstate, property_segment);
|
367
414
|
lex< exactly<':'> >();
|
368
415
|
|
369
|
-
if (!peek< exactly<'{'> >()) error("expected a '{' after namespaced property");
|
416
|
+
if (!peek< exactly<'{'> >()) error("expected a '{' after namespaced property", pstate);
|
370
417
|
|
371
418
|
propset->block(parse_block());
|
372
419
|
|
420
|
+
propset->tabs(indentation);
|
421
|
+
|
373
422
|
return propset;
|
374
|
-
}
|
423
|
+
} */
|
375
424
|
|
376
425
|
Ruleset* Parser::parse_ruleset(Selector_Lookahead lookahead)
|
377
426
|
{
|
@@ -382,10 +431,14 @@ namespace Sass {
|
|
382
431
|
else {
|
383
432
|
sel = parse_selector_group();
|
384
433
|
}
|
385
|
-
|
386
|
-
|
434
|
+
bool old_in_at_root = in_at_root;
|
435
|
+
in_at_root = false;
|
436
|
+
ParserState r_source_position = pstate;
|
437
|
+
if (!peek< exactly<'{'> >()) error("expected a '{' after the selector", pstate);
|
387
438
|
Block* block = parse_block();
|
388
|
-
|
439
|
+
in_at_root = old_in_at_root;
|
440
|
+
old_in_at_root = false;
|
441
|
+
Ruleset* ruleset = new (ctx.mem) Ruleset(r_source_position, sel, block);
|
389
442
|
return ruleset;
|
390
443
|
}
|
391
444
|
|
@@ -393,66 +446,91 @@ namespace Sass {
|
|
393
446
|
{
|
394
447
|
lex< optional_spaces >();
|
395
448
|
const char* i = position;
|
396
|
-
|
397
|
-
String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
|
398
|
-
|
449
|
+
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
|
399
450
|
while (i < end_of_selector) {
|
400
|
-
|
401
|
-
if (p) {
|
402
|
-
// accumulate the preceding segment if
|
403
|
-
if (i < p) (*schema) << new (ctx.mem)
|
404
|
-
//
|
405
|
-
const char* j =
|
406
|
-
Expression*
|
407
|
-
|
408
|
-
(*schema) <<
|
409
|
-
i = j
|
410
|
-
}
|
411
|
-
|
412
|
-
|
451
|
+
// try to parse mutliple interpolants
|
452
|
+
if (const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, end_of_selector)) {
|
453
|
+
// accumulate the preceding segment if the position has advanced
|
454
|
+
if (i < p) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
|
455
|
+
// skip to the delimiter by skipping occurences in quoted strings
|
456
|
+
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
|
457
|
+
Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
|
458
|
+
interpolant->is_interpolant(true);
|
459
|
+
(*schema) << interpolant;
|
460
|
+
i = j;
|
461
|
+
}
|
462
|
+
// no more interpolants have been found
|
463
|
+
// add the last segment if there is one
|
464
|
+
else {
|
465
|
+
if (i < end_of_selector) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, end_of_selector));
|
413
466
|
break;
|
414
467
|
}
|
415
468
|
}
|
416
469
|
position = end_of_selector;
|
417
|
-
|
470
|
+
Selector_Schema* selector_schema = new (ctx.mem) Selector_Schema(pstate, schema);
|
471
|
+
selector_schema->media_block(last_media_block);
|
472
|
+
selector_schema->last_block(block_stack.back());
|
473
|
+
return selector_schema;
|
418
474
|
}
|
419
475
|
|
420
476
|
Selector_List* Parser::parse_selector_group()
|
421
477
|
{
|
422
|
-
|
423
|
-
|
424
|
-
|
478
|
+
bool reloop = true;
|
479
|
+
To_String to_string(&ctx);
|
480
|
+
lex< optional_spaces_and_comments >();
|
481
|
+
Selector_List* group = new (ctx.mem) Selector_List(pstate);
|
482
|
+
group->media_block(last_media_block);
|
483
|
+
group->last_block(block_stack.back());
|
425
484
|
do {
|
485
|
+
reloop = false;
|
426
486
|
if (peek< exactly<'{'> >() ||
|
427
487
|
peek< exactly<'}'> >() ||
|
428
488
|
peek< exactly<')'> >() ||
|
429
489
|
peek< exactly<';'> >())
|
430
490
|
break; // in case there are superfluous commas at the end
|
431
491
|
Complex_Selector* comb = parse_selector_combination();
|
432
|
-
if (!comb->has_reference()) {
|
433
|
-
|
434
|
-
Selector_Reference* ref = new (ctx.mem) Selector_Reference(
|
435
|
-
Compound_Selector* ref_wrap = new (ctx.mem) Compound_Selector(
|
492
|
+
if (!comb->has_reference() && !in_at_root) {
|
493
|
+
ParserState sel_source_position = pstate;
|
494
|
+
Selector_Reference* ref = new (ctx.mem) Selector_Reference(sel_source_position);
|
495
|
+
Compound_Selector* ref_wrap = new (ctx.mem) Compound_Selector(sel_source_position);
|
496
|
+
ref_wrap->media_block(last_media_block);
|
497
|
+
ref_wrap->last_block(block_stack.back());
|
436
498
|
(*ref_wrap) << ref;
|
437
499
|
if (!comb->head()) {
|
438
500
|
comb->head(ref_wrap);
|
439
501
|
comb->has_reference(true);
|
440
502
|
}
|
441
503
|
else {
|
442
|
-
comb = new (ctx.mem) Complex_Selector(
|
504
|
+
comb = new (ctx.mem) Complex_Selector(sel_source_position, Complex_Selector::ANCESTOR_OF, ref_wrap, comb);
|
505
|
+
comb->media_block(last_media_block);
|
506
|
+
comb->last_block(block_stack.back());
|
443
507
|
comb->has_reference(true);
|
444
508
|
}
|
509
|
+
if (peek_newline()) ref_wrap->has_line_break(true);
|
510
|
+
}
|
511
|
+
while (peek< sequence< optional_spaces_and_comments, exactly<','> > >())
|
512
|
+
{
|
513
|
+
// consume everything up and including the comma speparator
|
514
|
+
reloop = lex< sequence< optional_spaces_and_comments, exactly<','> > >() != 0;
|
515
|
+
// remember line break (also between some commas)
|
516
|
+
if (peek_newline()) comb->has_line_feed(true);
|
517
|
+
if (comb->tail() && peek_newline()) comb->tail()->has_line_feed(true);
|
518
|
+
if (comb->tail() && comb->tail()->head() && peek_newline()) comb->tail()->head()->has_line_feed(true);
|
519
|
+
// remember line break (also between some commas)
|
445
520
|
}
|
446
521
|
(*group) << comb;
|
447
522
|
}
|
448
|
-
while (
|
449
|
-
while (lex< optional >())
|
523
|
+
while (reloop);
|
524
|
+
while (lex< optional >()) {
|
525
|
+
group->is_optional(true);
|
526
|
+
}
|
450
527
|
return group;
|
451
528
|
}
|
452
529
|
|
453
530
|
Complex_Selector* Parser::parse_selector_combination()
|
454
531
|
{
|
455
|
-
|
532
|
+
// lex< optional_spaces_and_comments >();
|
533
|
+
Position sel_source_position(-1);
|
456
534
|
Compound_Selector* lhs;
|
457
535
|
if (peek< exactly<'+'> >() ||
|
458
536
|
peek< exactly<'~'> >() ||
|
@@ -462,7 +540,8 @@ namespace Sass {
|
|
462
540
|
}
|
463
541
|
else {
|
464
542
|
lhs = parse_simple_selector_sequence();
|
465
|
-
sel_source_position =
|
543
|
+
sel_source_position = before_token;
|
544
|
+
lhs->has_line_break(peek_newline());
|
466
545
|
}
|
467
546
|
|
468
547
|
Complex_Selector::Combinator cmb;
|
@@ -470,6 +549,7 @@ namespace Sass {
|
|
470
549
|
else if (lex< exactly<'~'> >()) cmb = Complex_Selector::PRECEDES;
|
471
550
|
else if (lex< exactly<'>'> >()) cmb = Complex_Selector::PARENT_OF;
|
472
551
|
else cmb = Complex_Selector::ANCESTOR_OF;
|
552
|
+
bool cpx_lf = peek_newline();
|
473
553
|
|
474
554
|
Complex_Selector* rhs;
|
475
555
|
if (peek< exactly<','> >() ||
|
@@ -483,31 +563,40 @@ namespace Sass {
|
|
483
563
|
}
|
484
564
|
else {
|
485
565
|
rhs = parse_selector_combination();
|
486
|
-
sel_source_position =
|
566
|
+
sel_source_position = before_token;
|
487
567
|
}
|
488
|
-
if (!sel_source_position.line) sel_source_position =
|
489
|
-
|
568
|
+
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);
|
570
|
+
cpx->media_block(last_media_block);
|
571
|
+
cpx->last_block(block_stack.back());
|
572
|
+
if (cpx_lf) cpx->has_line_break(cpx_lf);
|
573
|
+
return cpx;
|
490
574
|
}
|
491
575
|
|
492
576
|
Compound_Selector* Parser::parse_simple_selector_sequence()
|
493
577
|
{
|
494
|
-
Compound_Selector* seq = new (ctx.mem) Compound_Selector(
|
578
|
+
Compound_Selector* seq = new (ctx.mem) Compound_Selector(pstate);
|
579
|
+
seq->media_block(last_media_block);
|
580
|
+
seq->last_block(block_stack.back());
|
495
581
|
bool sawsomething = false;
|
496
582
|
if (lex< exactly<'&'> >()) {
|
497
|
-
// if
|
498
|
-
(
|
583
|
+
// check if we have a parent selector on the root level block
|
584
|
+
if (block_stack.back() && block_stack.back()->is_root()) {
|
585
|
+
error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
|
586
|
+
}
|
587
|
+
(*seq) << new (ctx.mem) Selector_Reference(pstate);
|
499
588
|
sawsomething = true;
|
500
589
|
// if you see a space after a &, then you're done
|
501
|
-
if(
|
590
|
+
if(peek< spaces >()) {
|
502
591
|
return seq;
|
503
592
|
}
|
504
593
|
}
|
505
|
-
if (sawsomething && lex< sequence< negate< functional >, alternatives< identifier_fragment, universal,
|
594
|
+
if (sawsomething && lex< sequence< negate< functional >, alternatives< identifier_fragment, universal, quoted_string, dimension, percentage, number > > >()) {
|
506
595
|
// saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
|
507
|
-
(*seq) << new (ctx.mem) Type_Selector(
|
508
|
-
} else if (lex< sequence< negate< functional >, alternatives< type_selector, universal,
|
596
|
+
(*seq) << new (ctx.mem) Type_Selector(pstate, unquote(lexed));
|
597
|
+
} else if (lex< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
|
509
598
|
// if you see a type selector
|
510
|
-
(*seq) << new (ctx.mem) Type_Selector(
|
599
|
+
(*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
|
511
600
|
sawsomething = true;
|
512
601
|
}
|
513
602
|
if (!sawsomething) {
|
@@ -532,10 +621,10 @@ namespace Sass {
|
|
532
621
|
Simple_Selector* Parser::parse_simple_selector()
|
533
622
|
{
|
534
623
|
if (lex< id_name >() || lex< class_name >()) {
|
535
|
-
return new (ctx.mem) Selector_Qualifier(
|
624
|
+
return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
|
536
625
|
}
|
537
|
-
else if (lex<
|
538
|
-
return new (ctx.mem) Type_Selector(
|
626
|
+
else if (lex< quoted_string >() || lex< number >()) {
|
627
|
+
return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
|
539
628
|
}
|
540
629
|
else if (peek< pseudo_not >()) {
|
541
630
|
return parse_negated_selector();
|
@@ -547,10 +636,13 @@ namespace Sass {
|
|
547
636
|
return parse_attribute_selector();
|
548
637
|
}
|
549
638
|
else if (lex< placeholder >()) {
|
550
|
-
|
639
|
+
Selector_Placeholder* sel = new (ctx.mem) Selector_Placeholder(pstate, unquote(lexed));
|
640
|
+
sel->media_block(last_media_block);
|
641
|
+
sel->last_block(block_stack.back());
|
642
|
+
return sel;
|
551
643
|
}
|
552
644
|
else {
|
553
|
-
error("invalid selector after " + lexed.to_string());
|
645
|
+
error("invalid selector after " + lexed.to_string(), pstate);
|
554
646
|
}
|
555
647
|
// unreachable statement
|
556
648
|
return 0;
|
@@ -560,73 +652,73 @@ namespace Sass {
|
|
560
652
|
{
|
561
653
|
lex< pseudo_not >();
|
562
654
|
string name(lexed);
|
563
|
-
|
655
|
+
ParserState nsource_position = pstate;
|
564
656
|
Selector* negated = parse_selector_group();
|
565
657
|
if (!lex< exactly<')'> >()) {
|
566
|
-
error("negated selector is missing ')'");
|
658
|
+
error("negated selector is missing ')'", pstate);
|
567
659
|
}
|
568
|
-
return new (ctx.mem) Wrapped_Selector(
|
660
|
+
return new (ctx.mem) Wrapped_Selector(nsource_position, name, negated);
|
569
661
|
}
|
570
662
|
|
571
663
|
Simple_Selector* Parser::parse_pseudo_selector() {
|
572
664
|
if (lex< sequence< pseudo_prefix, functional > >() || lex< functional >()) {
|
573
665
|
string name(lexed);
|
574
666
|
String* expr = 0;
|
575
|
-
|
667
|
+
ParserState p = pstate;
|
576
668
|
Selector* wrapped = 0;
|
577
669
|
if (lex< alternatives< even, odd > >()) {
|
578
|
-
expr = new (ctx.mem)
|
670
|
+
expr = new (ctx.mem) String_Quoted(p, lexed);
|
579
671
|
}
|
580
672
|
else if (peek< binomial >(position)) {
|
581
673
|
lex< sequence< optional< coefficient >, exactly<'n'> > >();
|
582
|
-
String_Constant* var_coef = new (ctx.mem)
|
674
|
+
String_Constant* var_coef = new (ctx.mem) String_Quoted(p, lexed);
|
583
675
|
lex< sign >();
|
584
|
-
String_Constant* op = new (ctx.mem)
|
676
|
+
String_Constant* op = new (ctx.mem) String_Quoted(p, lexed);
|
585
677
|
// Binary_Expression::Type op = (lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
|
586
678
|
lex< digits >();
|
587
|
-
String_Constant* constant = new (ctx.mem)
|
588
|
-
// expr = new (ctx.mem) Binary_Expression(
|
589
|
-
String_Schema* schema = new (ctx.mem) String_Schema(
|
679
|
+
String_Constant* constant = new (ctx.mem) String_Quoted(p, lexed);
|
680
|
+
// expr = new (ctx.mem) Binary_Expression(p, op, var_coef, constant);
|
681
|
+
String_Schema* schema = new (ctx.mem) String_Schema(p, 3);
|
590
682
|
*schema << var_coef << op << constant;
|
591
683
|
expr = schema;
|
592
684
|
}
|
593
685
|
else if (peek< sequence< optional<sign>,
|
594
686
|
optional<digits>,
|
595
687
|
exactly<'n'>,
|
596
|
-
|
688
|
+
optional_spaces_and_comments,
|
597
689
|
exactly<')'> > >()) {
|
598
690
|
lex< sequence< optional<sign>,
|
599
691
|
optional<digits>,
|
600
692
|
exactly<'n'> > >();
|
601
|
-
expr = new (ctx.mem)
|
693
|
+
expr = new (ctx.mem) String_Quoted(p, lexed);
|
602
694
|
}
|
603
695
|
else if (lex< sequence< optional<sign>, digits > >()) {
|
604
|
-
expr = new (ctx.mem)
|
696
|
+
expr = new (ctx.mem) String_Quoted(p, lexed);
|
605
697
|
}
|
606
|
-
else if (peek< sequence< identifier,
|
698
|
+
else if (peek< sequence< identifier, optional_spaces_and_comments, exactly<')'> > >()) {
|
607
699
|
lex< identifier >();
|
608
|
-
expr = new (ctx.mem)
|
700
|
+
expr = new (ctx.mem) String_Quoted(p, lexed);
|
609
701
|
}
|
610
|
-
else if (lex<
|
611
|
-
expr = new (ctx.mem)
|
702
|
+
else if (lex< quoted_string >()) {
|
703
|
+
expr = new (ctx.mem) String_Quoted(p, lexed);
|
612
704
|
}
|
613
705
|
else if (peek< exactly<')'> >()) {
|
614
|
-
expr = new (ctx.mem) String_Constant(
|
706
|
+
expr = new (ctx.mem) String_Constant(p, "");
|
615
707
|
}
|
616
708
|
else {
|
617
709
|
wrapped = parse_selector_group();
|
618
710
|
}
|
619
|
-
if (!lex< exactly<')'> >()) error("unterminated argument to " + name + "...)");
|
711
|
+
if (!lex< exactly<')'> >()) error("unterminated argument to " + name + "...)", pstate);
|
620
712
|
if (wrapped) {
|
621
|
-
return new (ctx.mem) Wrapped_Selector(
|
713
|
+
return new (ctx.mem) Wrapped_Selector(p, name, wrapped);
|
622
714
|
}
|
623
|
-
return new (ctx.mem) Pseudo_Selector(
|
715
|
+
return new (ctx.mem) Pseudo_Selector(p, name, expr);
|
624
716
|
}
|
625
717
|
else if (lex < sequence< pseudo_prefix, identifier > >()) {
|
626
|
-
return new (ctx.mem) Pseudo_Selector(
|
718
|
+
return new (ctx.mem) Pseudo_Selector(pstate, unquote(lexed));
|
627
719
|
}
|
628
720
|
else {
|
629
|
-
error("unrecognized pseudo-class or pseudo-element");
|
721
|
+
error("unrecognized pseudo-class or pseudo-element", pstate);
|
630
722
|
}
|
631
723
|
// unreachable statement
|
632
724
|
return 0;
|
@@ -635,29 +727,29 @@ namespace Sass {
|
|
635
727
|
Attribute_Selector* Parser::parse_attribute_selector()
|
636
728
|
{
|
637
729
|
lex< exactly<'['> >();
|
638
|
-
|
639
|
-
if (!lex< attribute_name >()) error("invalid attribute name in attribute selector");
|
730
|
+
ParserState p = pstate;
|
731
|
+
if (!lex< attribute_name >()) error("invalid attribute name in attribute selector", pstate);
|
640
732
|
string name(lexed);
|
641
|
-
if (lex< exactly<']'> >()) return new (ctx.mem) Attribute_Selector(
|
733
|
+
if (lex< exactly<']'> >()) return new (ctx.mem) Attribute_Selector(p, name, "", 0);
|
642
734
|
if (!lex< alternatives< exact_match, class_match, dash_match,
|
643
735
|
prefix_match, suffix_match, substring_match > >()) {
|
644
|
-
error("invalid operator in attribute selector for " + name);
|
736
|
+
error("invalid operator in attribute selector for " + name, pstate);
|
645
737
|
}
|
646
738
|
string matcher(lexed);
|
647
739
|
|
648
740
|
String* value = 0;
|
649
741
|
if (lex< identifier >()) {
|
650
|
-
value = new (ctx.mem) String_Constant(
|
742
|
+
value = new (ctx.mem) String_Constant(p, lexed);
|
651
743
|
}
|
652
|
-
else if (lex<
|
653
|
-
value = parse_interpolated_chunk(lexed);
|
744
|
+
else if (lex< quoted_string >()) {
|
745
|
+
value = parse_interpolated_chunk(lexed, true); // needed!
|
654
746
|
}
|
655
747
|
else {
|
656
|
-
error("expected a string constant or identifier in attribute selector for " + name);
|
748
|
+
error("expected a string constant or identifier in attribute selector for " + name, pstate);
|
657
749
|
}
|
658
750
|
|
659
|
-
if (!lex< exactly<']'> >()) error("unterminated attribute selector for " + name);
|
660
|
-
return new (ctx.mem) Attribute_Selector(
|
751
|
+
if (!lex< exactly<']'> >()) error("unterminated attribute selector for " + name, pstate);
|
752
|
+
return new (ctx.mem) Attribute_Selector(p, name, matcher, value);
|
661
753
|
}
|
662
754
|
|
663
755
|
Block* Parser::parse_block()
|
@@ -665,43 +757,47 @@ namespace Sass {
|
|
665
757
|
lex< exactly<'{'> >();
|
666
758
|
bool semicolon = false;
|
667
759
|
Selector_Lookahead lookahead_result;
|
668
|
-
Block* block = new (ctx.mem) Block(
|
669
|
-
|
760
|
+
Block* block = new (ctx.mem) Block(pstate);
|
761
|
+
block_stack.push_back(block);
|
762
|
+
lex< zero_plus < alternatives < space, line_comment > > >();
|
670
763
|
// JMA - ensure that a block containing only block_comments is parsed
|
671
764
|
while (lex< block_comment >()) {
|
765
|
+
bool is_important = lexed.begin[2] == '!';
|
672
766
|
String* contents = parse_interpolated_chunk(lexed);
|
673
|
-
Comment* comment = new (ctx.mem) Comment(
|
767
|
+
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
674
768
|
(*block) << comment;
|
675
769
|
}
|
676
770
|
|
677
771
|
while (!lex< exactly<'}'> >()) {
|
678
772
|
if (semicolon) {
|
679
773
|
if (!lex< one_plus< exactly<';'> > >()) {
|
680
|
-
error("non-terminal statement or declaration must end with ';'");
|
774
|
+
error("non-terminal statement or declaration must end with ';'", pstate);
|
681
775
|
}
|
682
776
|
semicolon = false;
|
683
777
|
while (lex< block_comment >()) {
|
778
|
+
bool is_important = lexed.begin[2] == '!';
|
684
779
|
String* contents = parse_interpolated_chunk(lexed);
|
685
|
-
Comment* comment = new (ctx.mem) Comment(
|
780
|
+
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
686
781
|
(*block) << comment;
|
687
782
|
}
|
688
783
|
if (lex< sequence< exactly<'}'>, zero_plus< exactly<';'> > > >()) break;
|
689
784
|
}
|
690
785
|
if (lex< block_comment >()) {
|
786
|
+
bool is_important = lexed.begin[2] == '!';
|
691
787
|
String* contents = parse_interpolated_chunk(lexed);
|
692
|
-
Comment* comment = new (ctx.mem) Comment(
|
788
|
+
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
693
789
|
(*block) << comment;
|
694
790
|
}
|
695
791
|
else if (peek< import >(position)) {
|
696
792
|
if (stack.back() == mixin_def || stack.back() == function_def) {
|
697
|
-
lex< import >(); // to adjust the
|
698
|
-
error("@import directives are not allowed inside mixins and functions");
|
793
|
+
lex< import >(); // to adjust the before_token number
|
794
|
+
error("@import directives are not allowed inside mixins and functions", pstate);
|
699
795
|
}
|
700
796
|
Import* imp = parse_import();
|
701
797
|
if (!imp->urls().empty()) (*block) << imp;
|
702
798
|
if (!imp->files().empty()) {
|
703
799
|
for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
|
704
|
-
(*block) << new (ctx.mem) Import_Stub(
|
800
|
+
(*block) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
|
705
801
|
}
|
706
802
|
}
|
707
803
|
semicolon = true;
|
@@ -710,6 +806,9 @@ namespace Sass {
|
|
710
806
|
(*block) << parse_assignment();
|
711
807
|
semicolon = true;
|
712
808
|
}
|
809
|
+
else if (lex< line_comment >()) {
|
810
|
+
// throw line comments away
|
811
|
+
}
|
713
812
|
else if (peek< if_directive >()) {
|
714
813
|
(*block) << parse_if_directive();
|
715
814
|
}
|
@@ -723,7 +822,7 @@ namespace Sass {
|
|
723
822
|
(*block) << parse_while_directive();
|
724
823
|
}
|
725
824
|
else if (lex < return_directive >()) {
|
726
|
-
(*block) << new (ctx.mem) Return(
|
825
|
+
(*block) << new (ctx.mem) Return(pstate, parse_list());
|
727
826
|
semicolon = true;
|
728
827
|
}
|
729
828
|
else if (peek< warn >()) {
|
@@ -739,7 +838,7 @@ namespace Sass {
|
|
739
838
|
semicolon = true;
|
740
839
|
}
|
741
840
|
else if (stack.back() == function_def) {
|
742
|
-
error("only variable declarations and control directives are allowed inside functions");
|
841
|
+
error("only variable declarations and control directives are allowed inside functions", pstate);
|
743
842
|
}
|
744
843
|
else if (peek< mixin >() || peek< function >()) {
|
745
844
|
(*block) << parse_definition();
|
@@ -752,9 +851,9 @@ namespace Sass {
|
|
752
851
|
}
|
753
852
|
else if (lex< content >()) {
|
754
853
|
if (stack.back() != mixin_def) {
|
755
|
-
error("@content may only be used within a mixin");
|
854
|
+
error("@content may only be used within a mixin", pstate);
|
756
855
|
}
|
757
|
-
(*block) << new (ctx.mem) Content(
|
856
|
+
(*block) << new (ctx.mem) Content(pstate);
|
758
857
|
semicolon = true;
|
759
858
|
}
|
760
859
|
/*
|
@@ -765,11 +864,11 @@ namespace Sass {
|
|
765
864
|
*/
|
766
865
|
else if (lex< extend >()) {
|
767
866
|
Selector_Lookahead lookahead = lookahead_for_extension_target(position);
|
768
|
-
if (!lookahead.found) error("invalid selector for @extend");
|
867
|
+
if (!lookahead.found) error("invalid selector for @extend", pstate);
|
769
868
|
Selector* target;
|
770
869
|
if (lookahead.has_interpolants) target = parse_selector_schema(lookahead.found);
|
771
870
|
else target = parse_selector_group();
|
772
|
-
(*block) << new (ctx.mem) Extension(
|
871
|
+
(*block) << new (ctx.mem) Extension(pstate, target);
|
773
872
|
semicolon = true;
|
774
873
|
}
|
775
874
|
else if (peek< media >()) {
|
@@ -778,9 +877,12 @@ namespace Sass {
|
|
778
877
|
else if (peek< supports >()) {
|
779
878
|
(*block) << parse_feature_block();
|
780
879
|
}
|
880
|
+
else if (peek< at_root >()) {
|
881
|
+
(*block) << parse_at_root_block();
|
882
|
+
}
|
781
883
|
// ignore the @charset directive for now
|
782
884
|
else if (lex< exactly< charset_kwd > >()) {
|
783
|
-
lex<
|
885
|
+
lex< quoted_string >();
|
784
886
|
lex< one_plus< exactly<';'> > >();
|
785
887
|
}
|
786
888
|
else if (peek< at_keyword >()) {
|
@@ -790,23 +892,28 @@ namespace Sass {
|
|
790
892
|
}
|
791
893
|
else if ((lookahead_result = lookahead_for_selector(position)).found) {
|
792
894
|
(*block) << parse_ruleset(lookahead_result);
|
793
|
-
}
|
895
|
+
}/* not used anymore - remove?
|
794
896
|
else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
|
795
897
|
(*block) << parse_propset();
|
796
|
-
}
|
898
|
+
}*/
|
797
899
|
else if (!peek< exactly<';'> >()) {
|
900
|
+
bool indent = ! peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position);
|
901
|
+
/* not used anymore - remove?
|
798
902
|
if (peek< sequence< optional< exactly<'*'> >, identifier_schema, exactly<':'>, exactly<'{'> > >()) {
|
799
903
|
(*block) << parse_propset();
|
800
904
|
}
|
801
905
|
else if (peek< sequence< optional< exactly<'*'> >, identifier, exactly<':'>, exactly<'{'> > >()) {
|
802
906
|
(*block) << parse_propset();
|
803
907
|
}
|
804
|
-
else {
|
908
|
+
else */ {
|
805
909
|
Declaration* decl = parse_declaration();
|
910
|
+
decl->tabs(indentation);
|
806
911
|
(*block) << decl;
|
807
912
|
if (peek< exactly<'{'> >()) {
|
808
913
|
// parse a propset that rides on the declaration's property
|
809
|
-
|
914
|
+
if (indent) indentation++;
|
915
|
+
Propset* ps = new (ctx.mem) Propset(pstate, decl->property(), parse_block());
|
916
|
+
if (indent) indentation--;
|
810
917
|
(*block) << ps;
|
811
918
|
}
|
812
919
|
else {
|
@@ -817,11 +924,13 @@ namespace Sass {
|
|
817
924
|
}
|
818
925
|
else lex< one_plus< exactly<';'> > >();
|
819
926
|
while (lex< block_comment >()) {
|
927
|
+
bool is_important = lexed.begin[2] == '!';
|
820
928
|
String* contents = parse_interpolated_chunk(lexed);
|
821
|
-
Comment* comment = new (ctx.mem) Comment(
|
929
|
+
Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
|
822
930
|
(*block) << comment;
|
823
931
|
}
|
824
932
|
}
|
933
|
+
block_stack.pop_back();
|
825
934
|
return block;
|
826
935
|
}
|
827
936
|
|
@@ -831,27 +940,43 @@ namespace Sass {
|
|
831
940
|
prop = parse_identifier_schema();
|
832
941
|
}
|
833
942
|
else if (lex< sequence< optional< exactly<'*'> >, identifier > >()) {
|
834
|
-
prop = new (ctx.mem)
|
943
|
+
prop = new (ctx.mem) String_Quoted(pstate, lexed);
|
835
944
|
}
|
836
945
|
else if (lex< custom_property_name >()) {
|
837
|
-
prop = new (ctx.mem)
|
946
|
+
prop = new (ctx.mem) String_Quoted(pstate, lexed);
|
838
947
|
}
|
839
948
|
else {
|
840
|
-
error("invalid property name");
|
949
|
+
error("invalid property name", pstate);
|
841
950
|
}
|
842
|
-
if (!lex< one_plus< exactly<':'> > >()) error("property \"" + string(lexed) + "\" must be followed by a ':'");
|
843
|
-
if (peek< exactly<';'> >()) error("style declaration must contain a value");
|
951
|
+
if (!lex< one_plus< exactly<':'> > >()) error("property \"" + string(lexed) + "\" must be followed by a ':'", pstate);
|
952
|
+
if (peek< exactly<';'> >()) error("style declaration must contain a value", pstate);
|
844
953
|
if (peek< static_value >()) {
|
845
|
-
return new (ctx.mem) Declaration(
|
954
|
+
return new (ctx.mem) Declaration(prop->pstate(), prop, parse_static_value()/*, lex<important>()*/);
|
846
955
|
}
|
847
956
|
else {
|
848
|
-
return new (ctx.mem) Declaration(
|
957
|
+
return new (ctx.mem) Declaration(prop->pstate(), prop, parse_list()/*, lex<important>()*/);
|
958
|
+
}
|
959
|
+
}
|
960
|
+
|
961
|
+
// parse +/- and return false if negative
|
962
|
+
bool Parser::parse_number_prefix()
|
963
|
+
{
|
964
|
+
bool positive = true;
|
965
|
+
while(true) {
|
966
|
+
if (lex < block_comment >()) continue;
|
967
|
+
if (lex < number_prefix >()) continue;
|
968
|
+
if (lex < exactly < '-' > >()) {
|
969
|
+
positive = !positive;
|
970
|
+
continue;
|
971
|
+
}
|
972
|
+
break;
|
849
973
|
}
|
974
|
+
return positive;
|
850
975
|
}
|
851
976
|
|
852
977
|
Expression* Parser::parse_map()
|
853
978
|
{
|
854
|
-
To_String to_string;
|
979
|
+
To_String to_string(&ctx);
|
855
980
|
Expression* key = parse_list();
|
856
981
|
|
857
982
|
// it's not a map so return the lexed value as a list value
|
@@ -862,7 +987,7 @@ namespace Sass {
|
|
862
987
|
|
863
988
|
Expression* value = parse_space_list();
|
864
989
|
|
865
|
-
Map* map = new (ctx.mem) Map(
|
990
|
+
Map* map = new (ctx.mem) Map(pstate, 1);
|
866
991
|
(*map) << make_pair(key, value);
|
867
992
|
|
868
993
|
while (lex< exactly<','> >())
|
@@ -874,7 +999,7 @@ namespace Sass {
|
|
874
999
|
Expression* key = parse_list();
|
875
1000
|
|
876
1001
|
if (!(lex< exactly<':'> >()))
|
877
|
-
{ error("invalid syntax"); }
|
1002
|
+
{ error("invalid syntax", pstate); }
|
878
1003
|
|
879
1004
|
Expression* value = parse_space_list();
|
880
1005
|
|
@@ -882,7 +1007,7 @@ namespace Sass {
|
|
882
1007
|
}
|
883
1008
|
|
884
1009
|
if (map->has_duplicate_key())
|
885
|
-
{ error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + "."); }
|
1010
|
+
{ error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + ".", pstate); }
|
886
1011
|
|
887
1012
|
return map;
|
888
1013
|
}
|
@@ -901,12 +1026,12 @@ namespace Sass {
|
|
901
1026
|
peek< exactly<')'> >(position) ||
|
902
1027
|
//peek< exactly<':'> >(position) ||
|
903
1028
|
peek< exactly<ellipsis> >(position))
|
904
|
-
{ return new (ctx.mem) List(
|
1029
|
+
{ return new (ctx.mem) List(pstate, 0); }
|
905
1030
|
Expression* list1 = parse_space_list();
|
906
1031
|
// if it's a singleton, return it directly; don't wrap it
|
907
1032
|
if (!peek< exactly<','> >(position)) return list1;
|
908
1033
|
|
909
|
-
List* comma_list = new (ctx.mem) List(
|
1034
|
+
List* comma_list = new (ctx.mem) List(pstate, 2, List::COMMA);
|
910
1035
|
(*comma_list) << list1;
|
911
1036
|
|
912
1037
|
while (lex< exactly<','> >())
|
@@ -943,7 +1068,7 @@ namespace Sass {
|
|
943
1068
|
peek< global_flag >(position))
|
944
1069
|
{ return disj1; }
|
945
1070
|
|
946
|
-
List* space_list = new (ctx.mem) List(
|
1071
|
+
List* space_list = new (ctx.mem) List(pstate, 2, List::SPACE);
|
947
1072
|
(*space_list) << disj1;
|
948
1073
|
|
949
1074
|
while (!(//peek< exactly<'!'> >(position) ||
|
@@ -1012,7 +1137,7 @@ namespace Sass {
|
|
1012
1137
|
|
1013
1138
|
Expression* expr2 = parse_expression();
|
1014
1139
|
|
1015
|
-
return new (ctx.mem) Binary_Expression(
|
1140
|
+
return new (ctx.mem) Binary_Expression(expr1->pstate(), op, expr1, expr2);
|
1016
1141
|
}
|
1017
1142
|
|
1018
1143
|
Expression* Parser::parse_expression()
|
@@ -1020,14 +1145,15 @@ namespace Sass {
|
|
1020
1145
|
Expression* term1 = parse_term();
|
1021
1146
|
// if it's a singleton, return it directly; don't wrap it
|
1022
1147
|
if (!(peek< exactly<'+'> >(position) ||
|
1023
|
-
peek< sequence< negate<
|
1148
|
+
(peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
|
1149
|
+
(peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
|
1024
1150
|
peek< identifier >(position))
|
1025
1151
|
{ return term1; }
|
1026
1152
|
|
1027
1153
|
vector<Expression*> operands;
|
1028
1154
|
vector<Binary_Expression::Type> operators;
|
1029
|
-
while (lex< exactly<'+'> >() || lex< sequence< negate<
|
1030
|
-
operators.push_back(lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
|
1155
|
+
while (lex< exactly<'+'> >() || lex< sequence< negate< digits >, exactly<'-'> > >()) {
|
1156
|
+
operators.push_back(lexed.to_string() == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
|
1031
1157
|
operands.push_back(parse_term());
|
1032
1158
|
}
|
1033
1159
|
|
@@ -1040,12 +1166,8 @@ namespace Sass {
|
|
1040
1166
|
|
1041
1167
|
// Special case: Ruby sass never tries to modulo if the lhs contains an interpolant
|
1042
1168
|
if (peek< exactly<'%'> >(position) && fact1->concrete_type() == Expression::STRING) {
|
1043
|
-
|
1044
|
-
|
1045
|
-
if (ss->has_interpolants()) return fact1;
|
1046
|
-
}
|
1047
|
-
catch (bad_cast&) {}
|
1048
|
-
catch (...) { throw; }
|
1169
|
+
String_Schema* ss = dynamic_cast<String_Schema*>(fact1);
|
1170
|
+
if (ss && ss->has_interpolants()) return fact1;
|
1049
1171
|
}
|
1050
1172
|
|
1051
1173
|
// if it's a singleton, return it directly; don't wrap it
|
@@ -1054,11 +1176,12 @@ namespace Sass {
|
|
1054
1176
|
peek< exactly<'%'> >(position)))
|
1055
1177
|
{ return fact1; }
|
1056
1178
|
|
1179
|
+
while (lex< block_comment >());
|
1057
1180
|
vector<Expression*> operands;
|
1058
1181
|
vector<Binary_Expression::Type> operators;
|
1059
1182
|
while (lex< exactly<'*'> >() || lex< exactly<'/'> >() || lex< exactly<'%'> >()) {
|
1060
|
-
if (lexed == "*") operators.push_back(Binary_Expression::MUL);
|
1061
|
-
else if (lexed == "/") operators.push_back(Binary_Expression::DIV);
|
1183
|
+
if (lexed.to_string() == "*") operators.push_back(Binary_Expression::MUL);
|
1184
|
+
else if (lexed.to_string() == "/") operators.push_back(Binary_Expression::DIV);
|
1062
1185
|
else operators.push_back(Binary_Expression::MOD);
|
1063
1186
|
operands.push_back(parse_factor());
|
1064
1187
|
}
|
@@ -1070,7 +1193,7 @@ namespace Sass {
|
|
1070
1193
|
{
|
1071
1194
|
if (lex< exactly<'('> >()) {
|
1072
1195
|
Expression* value = parse_map();
|
1073
|
-
if (!lex< exactly<')'> >()) error("unclosed parenthesis");
|
1196
|
+
if (!lex< exactly<')'> >()) error("unclosed parenthesis", pstate);
|
1074
1197
|
value->is_delayed(false);
|
1075
1198
|
// make sure wrapped lists and division expressions are non-delayed within parentheses
|
1076
1199
|
if (value->concrete_type() == Expression::LIST) {
|
@@ -1091,6 +1214,7 @@ namespace Sass {
|
|
1091
1214
|
}
|
1092
1215
|
else if (peek< exactly< calc_kwd > >() ||
|
1093
1216
|
peek< exactly< moz_calc_kwd > >() ||
|
1217
|
+
peek< exactly< ms_calc_kwd > >() ||
|
1094
1218
|
peek< exactly< webkit_calc_kwd > >()) {
|
1095
1219
|
return parse_calc_function();
|
1096
1220
|
}
|
@@ -1103,14 +1227,18 @@ namespace Sass {
|
|
1103
1227
|
else if (peek< functional >() && !peek< uri_prefix >()) {
|
1104
1228
|
return parse_function_call();
|
1105
1229
|
}
|
1106
|
-
else if (lex< sequence< exactly<'+'>,
|
1107
|
-
return new (ctx.mem) Unary_Expression(
|
1230
|
+
else if (lex< sequence< exactly<'+'>, optional_spaces_and_comments, negate< number > > >()) {
|
1231
|
+
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::PLUS, parse_factor());
|
1108
1232
|
}
|
1109
|
-
else if (lex< sequence< exactly<'-'>,
|
1110
|
-
return new (ctx.mem) Unary_Expression(
|
1233
|
+
else if (lex< sequence< exactly<'-'>, optional_spaces_and_comments, negate< number> > >()) {
|
1234
|
+
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_factor());
|
1111
1235
|
}
|
1112
1236
|
else if (lex< sequence< not_op, spaces_and_comments > >()) {
|
1113
|
-
return new (ctx.mem) Unary_Expression(
|
1237
|
+
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::NOT, parse_factor());
|
1238
|
+
}
|
1239
|
+
else if (peek < sequence < one_plus < alternatives < spaces_and_comments, exactly<'-'>, exactly<'+'> > >, number > >()) {
|
1240
|
+
if (parse_number_prefix()) return parse_value(); // prefix is positive
|
1241
|
+
return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_value());
|
1114
1242
|
}
|
1115
1243
|
else {
|
1116
1244
|
return parse_value();
|
@@ -1119,11 +1247,12 @@ namespace Sass {
|
|
1119
1247
|
|
1120
1248
|
Expression* Parser::parse_value()
|
1121
1249
|
{
|
1250
|
+
while (lex< block_comment >());
|
1122
1251
|
if (lex< uri_prefix >()) {
|
1123
|
-
Arguments* args = new (ctx.mem) Arguments(
|
1124
|
-
Function_Call* result = new (ctx.mem) Function_Call(
|
1252
|
+
Arguments* args = new (ctx.mem) Arguments(pstate);
|
1253
|
+
Function_Call* result = new (ctx.mem) Function_Call(pstate, "url", args);
|
1125
1254
|
const char* here = position;
|
1126
|
-
Position here_p =
|
1255
|
+
Position here_p = before_token;
|
1127
1256
|
// Try to parse a SassScript expression. If it succeeds and we can munch
|
1128
1257
|
// a matching rparen, then that's our url. If we can't munch a matching
|
1129
1258
|
// rparen, or if the attempt to parse an expression fails, then try to
|
@@ -1131,118 +1260,128 @@ namespace Sass {
|
|
1131
1260
|
try {
|
1132
1261
|
// special case -- if there's a comment, treat it as part of a URL
|
1133
1262
|
lex<spaces>();
|
1134
|
-
if (peek<line_comment_prefix>() || peek<block_comment_prefix>()) error("comment in URL"); // doesn't really matter what we throw
|
1263
|
+
if (peek<line_comment_prefix>() || peek<block_comment_prefix>()) error("comment in URL", pstate); // doesn't really matter what we throw
|
1135
1264
|
Expression* expr = parse_list();
|
1136
|
-
if (!lex< exactly<')'> >()) error("dangling expression in URL"); // doesn't really matter what we throw
|
1137
|
-
Argument* arg = new (ctx.mem) Argument(
|
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);
|
1138
1267
|
*args << arg;
|
1139
1268
|
return result;
|
1140
1269
|
}
|
1141
1270
|
catch (Sass_Error&) {
|
1142
1271
|
// back up so we can try again
|
1143
1272
|
position = here;
|
1144
|
-
|
1273
|
+
before_token = here_p;
|
1145
1274
|
}
|
1146
1275
|
catch (...) { throw; }
|
1147
1276
|
lex< spaces >();
|
1148
1277
|
if (lex< url >()) {
|
1149
1278
|
String* the_url = parse_interpolated_chunk(lexed);
|
1150
|
-
Argument* arg = new (ctx.mem) Argument(
|
1279
|
+
Argument* arg = new (ctx.mem) Argument(the_url->pstate(), the_url);
|
1151
1280
|
*args << arg;
|
1152
1281
|
}
|
1153
1282
|
else {
|
1154
|
-
error("malformed URL");
|
1283
|
+
error("malformed URL", pstate);
|
1155
1284
|
}
|
1156
|
-
if (!lex< exactly<')'> >()) error("URI is missing ')'");
|
1285
|
+
if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
|
1157
1286
|
return result;
|
1158
1287
|
}
|
1159
1288
|
|
1160
1289
|
if (lex< important >())
|
1161
|
-
{ return new (ctx.mem) String_Constant(
|
1290
|
+
{ return new (ctx.mem) String_Constant(pstate, "!important"); }
|
1162
1291
|
|
1163
|
-
|
1164
|
-
|
1292
|
+
const char* stop;
|
1293
|
+
if ((stop = peek< value_schema >()))
|
1294
|
+
{ return parse_value_schema(stop); }
|
1165
1295
|
|
1166
1296
|
if (lex< sequence< true_val, negate< identifier > > >())
|
1167
|
-
{ return new (ctx.mem) Boolean(
|
1297
|
+
{ return new (ctx.mem) Boolean(pstate, true); }
|
1168
1298
|
|
1169
1299
|
if (lex< sequence< false_val, negate< identifier > > >())
|
1170
|
-
{ return new (ctx.mem) Boolean(
|
1300
|
+
{ return new (ctx.mem) Boolean(pstate, false); }
|
1171
1301
|
|
1172
1302
|
if (lex< sequence< null, negate< identifier > > >())
|
1173
|
-
{ return new (ctx.mem) Null(
|
1303
|
+
{ return new (ctx.mem) Null(pstate); }
|
1174
1304
|
|
1175
1305
|
if (lex< identifier >()) {
|
1176
|
-
String_Constant* str = new (ctx.mem)
|
1306
|
+
String_Constant* str = new (ctx.mem) String_Quoted(pstate, lexed);
|
1177
1307
|
// Dont' delay this string if it is a name color. Fixes #652.
|
1178
|
-
str->is_delayed(ctx.names_to_colors.count(lexed) == 0);
|
1308
|
+
str->is_delayed(ctx.names_to_colors.count(unquote(lexed)) == 0);
|
1179
1309
|
return str;
|
1180
1310
|
}
|
1181
1311
|
|
1182
1312
|
if (lex< percentage >())
|
1183
|
-
{ return new (ctx.mem) Textual(
|
1313
|
+
{ return new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed); }
|
1184
1314
|
|
1185
|
-
|
1186
|
-
|
1315
|
+
// match hex number first because 0x000 looks like a number followed by an indentifier
|
1316
|
+
if (lex< alternatives< hex, hex0 > >())
|
1317
|
+
{ return new (ctx.mem) Textual(pstate, Textual::HEX, lexed); }
|
1187
1318
|
|
1188
|
-
|
1189
|
-
|
1319
|
+
// also handle the 10em- foo special case
|
1320
|
+
if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
|
1321
|
+
{ return new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed); }
|
1190
1322
|
|
1191
|
-
if (lex<
|
1192
|
-
{ return new (ctx.mem) Textual(
|
1323
|
+
if (lex< number >())
|
1324
|
+
{ return new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed); }
|
1193
1325
|
|
1194
|
-
if (peek<
|
1326
|
+
if (peek< quoted_string >())
|
1195
1327
|
{ return parse_string(); }
|
1196
1328
|
|
1197
1329
|
if (lex< variable >())
|
1198
|
-
{ return new (ctx.mem) Variable(
|
1330
|
+
{ return new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed)); }
|
1199
1331
|
|
1200
1332
|
// Special case handling for `%` proceeding an interpolant.
|
1201
1333
|
if (lex< sequence< exactly<'%'>, optional< percentage > > >())
|
1202
|
-
{ return new (ctx.mem)
|
1334
|
+
{ return new (ctx.mem) String_Quoted(pstate, lexed); }
|
1203
1335
|
|
1204
|
-
error("error reading values after " + lexed.to_string());
|
1336
|
+
error("error reading values after " + lexed.to_string(), pstate);
|
1205
1337
|
|
1206
1338
|
// unreachable statement
|
1207
1339
|
return 0;
|
1208
1340
|
}
|
1209
1341
|
|
1210
|
-
|
1342
|
+
// this parses interpolation inside other strings
|
1343
|
+
// means the result should later be quoted again
|
1344
|
+
String* Parser::parse_interpolated_chunk(Token chunk, bool constant)
|
1211
1345
|
{
|
1212
1346
|
const char* i = chunk.begin;
|
1213
1347
|
// see if there any interpolants
|
1214
|
-
const char* p = find_first_in_interval<
|
1348
|
+
const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
|
1215
1349
|
if (!p) {
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1350
|
+
String_Quoted* str_quoted = new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
|
1351
|
+
if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
|
1352
|
+
str_quoted->is_delayed(true);
|
1353
|
+
return str_quoted;
|
1219
1354
|
}
|
1220
1355
|
|
1221
|
-
String_Schema* schema = new (ctx.mem) String_Schema(
|
1222
|
-
schema->quote_mark(*chunk.begin);
|
1356
|
+
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
|
1223
1357
|
while (i < chunk.end) {
|
1224
|
-
p = find_first_in_interval<
|
1358
|
+
p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
|
1225
1359
|
if (p) {
|
1226
1360
|
if (i < p) {
|
1227
|
-
|
1361
|
+
// accumulate the preceding segment if it's nonempty
|
1362
|
+
(*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
|
1228
1363
|
}
|
1229
|
-
|
1230
|
-
|
1364
|
+
// we need to skip anything inside strings
|
1365
|
+
// create a new target in parser/prelexer
|
1366
|
+
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
|
1367
|
+
if (j) { --j;
|
1231
1368
|
// parse the interpolant and accumulate it
|
1232
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx,
|
1369
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
|
1233
1370
|
interp_node->is_interpolant(true);
|
1234
1371
|
(*schema) << interp_node;
|
1235
|
-
i = j
|
1372
|
+
i = j;
|
1236
1373
|
}
|
1237
1374
|
else {
|
1238
1375
|
// throw an error if the interpolant is unterminated
|
1239
|
-
error("unterminated interpolant inside string constant " + chunk.to_string());
|
1376
|
+
error("unterminated interpolant inside string constant " + chunk.to_string(), pstate);
|
1240
1377
|
}
|
1241
1378
|
}
|
1242
1379
|
else { // no interpolants left; add the last segment if nonempty
|
1243
|
-
|
1380
|
+
// check if we need quotes here (was not sure after merge)
|
1381
|
+
if (i < chunk.end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
|
1244
1382
|
break;
|
1245
1383
|
}
|
1384
|
+
++ i;
|
1246
1385
|
}
|
1247
1386
|
return schema;
|
1248
1387
|
}
|
@@ -1253,52 +1392,16 @@ namespace Sass {
|
|
1253
1392
|
Token str(lexed);
|
1254
1393
|
--str.end;
|
1255
1394
|
--position;
|
1256
|
-
String_Constant* str_node = new (ctx.mem) String_Constant(
|
1257
|
-
str_node->is_delayed(true);
|
1395
|
+
String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
|
1396
|
+
// str_node->is_delayed(true);
|
1258
1397
|
return str_node;
|
1259
1398
|
}
|
1260
1399
|
|
1261
1400
|
String* Parser::parse_string()
|
1262
1401
|
{
|
1263
|
-
lex<
|
1264
|
-
Token
|
1265
|
-
return parse_interpolated_chunk(
|
1266
|
-
// const char* i = str.begin;
|
1267
|
-
// // see if there any interpolants
|
1268
|
-
// const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(str.begin, str.end);
|
1269
|
-
// if (!p) {
|
1270
|
-
// String_Constant* str_node = new (ctx.mem) String_Constant(path, source_position, str);
|
1271
|
-
// str_node->is_delayed(true);
|
1272
|
-
// return str_node;
|
1273
|
-
// }
|
1274
|
-
|
1275
|
-
// String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
|
1276
|
-
// schema->quote_mark(*str.begin);
|
1277
|
-
// while (i < str.end) {
|
1278
|
-
// p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end);
|
1279
|
-
// if (p) {
|
1280
|
-
// if (i < p) {
|
1281
|
-
// (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, p)); // accumulate the preceding segment if it's nonempty
|
1282
|
-
// }
|
1283
|
-
// const char* j = find_first_in_interval< exactly<rbrace> >(p, str.end); // find the closing brace
|
1284
|
-
// if (j) {
|
1285
|
-
// // parse the interpolant and accumulate it
|
1286
|
-
// Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, path, source_position).parse_list();
|
1287
|
-
// interp_node->is_interpolant(true);
|
1288
|
-
// (*schema) << interp_node;
|
1289
|
-
// i = j+1;
|
1290
|
-
// }
|
1291
|
-
// else {
|
1292
|
-
// // throw an error if the interpolant is unterminated
|
1293
|
-
// error("unterminated interpolant inside string constant " + str.to_string());
|
1294
|
-
// }
|
1295
|
-
// }
|
1296
|
-
// else { // no interpolants left; add the last segment if nonempty
|
1297
|
-
// if (i < str.end) (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, str.end));
|
1298
|
-
// break;
|
1299
|
-
// }
|
1300
|
-
// }
|
1301
|
-
// return schema;
|
1402
|
+
lex< quoted_string >();
|
1403
|
+
Token token(lexed);
|
1404
|
+
return parse_interpolated_chunk(token);
|
1302
1405
|
}
|
1303
1406
|
|
1304
1407
|
String* Parser::parse_ie_property()
|
@@ -1307,35 +1410,35 @@ namespace Sass {
|
|
1307
1410
|
Token str(lexed);
|
1308
1411
|
const char* i = str.begin;
|
1309
1412
|
// see if there any interpolants
|
1310
|
-
const char* p = find_first_in_interval<
|
1413
|
+
const char* p = find_first_in_interval< exactly<hash_lbrace> >(str.begin, str.end);
|
1311
1414
|
if (!p) {
|
1312
|
-
String_Constant* str_node = new (ctx.mem) String_Constant(
|
1415
|
+
String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
|
1313
1416
|
str_node->is_delayed(true);
|
1314
1417
|
return str_node;
|
1315
1418
|
}
|
1316
1419
|
|
1317
|
-
String_Schema* schema = new (ctx.mem) String_Schema(
|
1420
|
+
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
|
1318
1421
|
while (i < str.end) {
|
1319
|
-
p = find_first_in_interval<
|
1422
|
+
p = find_first_in_interval< exactly<hash_lbrace> >(i, str.end);
|
1320
1423
|
if (p) {
|
1321
1424
|
if (i < p) {
|
1322
|
-
(*schema) << new (ctx.mem) String_Constant(
|
1425
|
+
(*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
|
1323
1426
|
}
|
1324
|
-
const char* j =
|
1427
|
+
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
|
1325
1428
|
if (j) {
|
1326
1429
|
// parse the interpolant and accumulate it
|
1327
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx,
|
1430
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
|
1328
1431
|
interp_node->is_interpolant(true);
|
1329
1432
|
(*schema) << interp_node;
|
1330
|
-
i = j
|
1433
|
+
i = j;
|
1331
1434
|
}
|
1332
1435
|
else {
|
1333
1436
|
// throw an error if the interpolant is unterminated
|
1334
|
-
error("unterminated interpolant inside IE function " + str.to_string());
|
1437
|
+
error("unterminated interpolant inside IE function " + str.to_string(), pstate);
|
1335
1438
|
}
|
1336
1439
|
}
|
1337
1440
|
else { // no interpolants left; add the last segment if nonempty
|
1338
|
-
if (i < str.end) (*schema) << new (ctx.mem) String_Constant(
|
1441
|
+
if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, string(i, str.end));
|
1339
1442
|
break;
|
1340
1443
|
}
|
1341
1444
|
}
|
@@ -1344,130 +1447,136 @@ namespace Sass {
|
|
1344
1447
|
|
1345
1448
|
String* Parser::parse_ie_keyword_arg()
|
1346
1449
|
{
|
1347
|
-
String_Schema* kwd_arg = new (ctx.mem) String_Schema(
|
1348
|
-
if (lex< variable >())
|
1349
|
-
|
1450
|
+
String_Schema* kwd_arg = new (ctx.mem) String_Schema(pstate, 3);
|
1451
|
+
if (lex< variable >()) {
|
1452
|
+
*kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
|
1453
|
+
} else {
|
1350
1454
|
lex< alternatives< identifier_schema, identifier > >();
|
1351
|
-
*kwd_arg << new (ctx.mem)
|
1455
|
+
*kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
|
1352
1456
|
}
|
1353
1457
|
lex< exactly<'='> >();
|
1354
|
-
*kwd_arg << new (ctx.mem)
|
1458
|
+
*kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
|
1355
1459
|
if (peek< variable >()) *kwd_arg << parse_list();
|
1356
|
-
else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(
|
1357
|
-
else {
|
1358
|
-
|
1359
|
-
*kwd_arg << new (ctx.mem) String_Constant(path, source_position, lexed);
|
1460
|
+
else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
|
1461
|
+
else if (lex< alternatives< identifier_schema, identifier, number, hexa, hex > >()) {
|
1462
|
+
*kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
|
1360
1463
|
}
|
1361
1464
|
return kwd_arg;
|
1362
1465
|
}
|
1363
1466
|
|
1364
|
-
String_Schema* Parser::parse_value_schema()
|
1467
|
+
String_Schema* Parser::parse_value_schema(const char* stop)
|
1365
1468
|
{
|
1366
|
-
String_Schema* schema = new (ctx.mem) String_Schema(
|
1469
|
+
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
|
1367
1470
|
size_t num_items = 0;
|
1368
|
-
while (position <
|
1471
|
+
while (position < stop) {
|
1369
1472
|
if (lex< interpolant >()) {
|
1370
|
-
Token insides(Token(lexed.begin + 2, lexed.end - 1));
|
1371
|
-
Expression* interp_node = Parser::from_token(insides, ctx,
|
1473
|
+
Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
|
1474
|
+
Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
|
1372
1475
|
interp_node->is_interpolant(true);
|
1373
1476
|
(*schema) << interp_node;
|
1374
1477
|
}
|
1375
1478
|
else if (lex< exactly<'%'> >()) {
|
1376
|
-
(*schema) << new (ctx.mem) String_Constant(
|
1479
|
+
(*schema) << new (ctx.mem) String_Constant(pstate, lexed);
|
1377
1480
|
}
|
1378
1481
|
else if (lex< identifier >()) {
|
1379
|
-
(*schema) << new (ctx.mem)
|
1482
|
+
(*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
|
1380
1483
|
}
|
1381
1484
|
else if (lex< percentage >()) {
|
1382
|
-
(*schema) << new (ctx.mem) Textual(
|
1485
|
+
(*schema) << new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed);
|
1383
1486
|
}
|
1384
1487
|
else if (lex< dimension >()) {
|
1385
|
-
(*schema) << new (ctx.mem) Textual(
|
1488
|
+
(*schema) << new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed);
|
1386
1489
|
}
|
1387
1490
|
else if (lex< number >()) {
|
1388
|
-
(*schema) << new (ctx.mem) Textual(
|
1491
|
+
(*schema) << new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
|
1389
1492
|
}
|
1390
1493
|
else if (lex< hex >()) {
|
1391
|
-
(*schema) << new (ctx.mem) Textual(
|
1494
|
+
(*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
|
1392
1495
|
}
|
1393
|
-
else if (lex<
|
1394
|
-
(*schema) << new (ctx.mem) String_Constant(
|
1395
|
-
if (!num_items) schema->quote_mark(*lexed.begin);
|
1496
|
+
else if (lex< quoted_string >()) {
|
1497
|
+
(*schema) << new (ctx.mem) String_Constant(pstate, lexed);
|
1396
1498
|
}
|
1397
1499
|
else if (lex< variable >()) {
|
1398
|
-
(*schema) << new (ctx.mem) Variable(
|
1500
|
+
(*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
|
1399
1501
|
}
|
1400
1502
|
else {
|
1401
|
-
error("error parsing interpolated value");
|
1503
|
+
error("error parsing interpolated value", pstate);
|
1402
1504
|
}
|
1403
1505
|
++num_items;
|
1404
1506
|
}
|
1405
1507
|
return schema;
|
1406
1508
|
}
|
1407
1509
|
|
1510
|
+
/* not used anymore - remove?
|
1408
1511
|
String_Schema* Parser::parse_url_schema()
|
1409
1512
|
{
|
1410
|
-
String_Schema* schema = new (ctx.mem) String_Schema(
|
1513
|
+
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
|
1411
1514
|
|
1412
1515
|
while (position < end) {
|
1413
1516
|
if (position[0] == '/') {
|
1414
|
-
lexed = Token(position, position+1);
|
1415
|
-
(*schema) << new (ctx.mem)
|
1517
|
+
lexed = Token(position, position+1, before_token);
|
1518
|
+
(*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
|
1416
1519
|
++position;
|
1417
1520
|
}
|
1418
1521
|
else if (lex< interpolant >()) {
|
1419
|
-
Token insides(Token(lexed.begin + 2, lexed.end - 1));
|
1420
|
-
Expression* interp_node = Parser::from_token(insides, ctx,
|
1522
|
+
Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
|
1523
|
+
Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
|
1421
1524
|
interp_node->is_interpolant(true);
|
1422
1525
|
(*schema) << interp_node;
|
1423
1526
|
}
|
1424
1527
|
else if (lex< sequence< identifier, exactly<':'> > >()) {
|
1425
|
-
(*schema) << new (ctx.mem)
|
1528
|
+
(*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
|
1426
1529
|
}
|
1427
1530
|
else if (lex< filename >()) {
|
1428
|
-
(*schema) << new (ctx.mem)
|
1531
|
+
(*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
|
1429
1532
|
}
|
1430
1533
|
else {
|
1431
|
-
error("error parsing interpolated url");
|
1534
|
+
error("error parsing interpolated url", pstate);
|
1432
1535
|
}
|
1433
1536
|
}
|
1434
1537
|
return schema;
|
1435
|
-
}
|
1538
|
+
} */
|
1436
1539
|
|
1540
|
+
// this parses interpolation outside other strings
|
1541
|
+
// means the result must not be quoted again later
|
1437
1542
|
String* Parser::parse_identifier_schema()
|
1438
1543
|
{
|
1544
|
+
// first lex away whatever we have found
|
1439
1545
|
lex< sequence< optional< exactly<'*'> >, identifier_schema > >();
|
1440
1546
|
Token id(lexed);
|
1441
1547
|
const char* i = id.begin;
|
1442
1548
|
// see if there any interpolants
|
1443
|
-
const char* p = find_first_in_interval<
|
1549
|
+
const char* p = find_first_in_interval< exactly<hash_lbrace> >(id.begin, id.end);
|
1444
1550
|
if (!p) {
|
1445
|
-
return new (ctx.mem)
|
1551
|
+
return new (ctx.mem) String_Quoted(pstate, string(id.begin, id.end));
|
1446
1552
|
}
|
1447
1553
|
|
1448
|
-
String_Schema* schema = new (ctx.mem) String_Schema(
|
1554
|
+
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
|
1449
1555
|
while (i < id.end) {
|
1450
|
-
p = find_first_in_interval<
|
1556
|
+
p = find_first_in_interval< exactly<hash_lbrace> >(i, id.end);
|
1451
1557
|
if (p) {
|
1452
1558
|
if (i < p) {
|
1453
|
-
|
1559
|
+
// accumulate the preceding segment if it's nonempty
|
1560
|
+
(*schema) << new (ctx.mem) String_Constant(pstate, string(i, p));
|
1454
1561
|
}
|
1455
|
-
|
1562
|
+
// we need to skip anything inside strings
|
1563
|
+
// create a new target in parser/prelexer
|
1564
|
+
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
|
1456
1565
|
if (j) {
|
1457
1566
|
// parse the interpolant and accumulate it
|
1458
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx,
|
1567
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
|
1459
1568
|
interp_node->is_interpolant(true);
|
1460
1569
|
(*schema) << interp_node;
|
1461
1570
|
schema->has_interpolants(true);
|
1462
|
-
i = j
|
1571
|
+
i = j;
|
1463
1572
|
}
|
1464
1573
|
else {
|
1465
1574
|
// throw an error if the interpolant is unterminated
|
1466
|
-
error("unterminated interpolant inside interpolated identifier " + id.to_string());
|
1575
|
+
error("unterminated interpolant inside interpolated identifier " + id.to_string(), pstate);
|
1467
1576
|
}
|
1468
1577
|
}
|
1469
1578
|
else { // no interpolants left; add the last segment if nonempty
|
1470
|
-
if (i <
|
1579
|
+
if (i < end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, id.end));
|
1471
1580
|
break;
|
1472
1581
|
}
|
1473
1582
|
}
|
@@ -1478,95 +1587,95 @@ namespace Sass {
|
|
1478
1587
|
{
|
1479
1588
|
lex< identifier >();
|
1480
1589
|
string name(lexed);
|
1481
|
-
|
1590
|
+
ParserState call_pos = pstate;
|
1482
1591
|
lex< exactly<'('> >();
|
1483
|
-
|
1592
|
+
ParserState arg_pos = pstate;
|
1484
1593
|
const char* arg_beg = position;
|
1485
1594
|
parse_list();
|
1486
1595
|
const char* arg_end = position;
|
1487
1596
|
lex< exactly<')'> >();
|
1488
1597
|
|
1489
|
-
Argument* arg = new (ctx.mem) Argument(
|
1490
|
-
Arguments* args = new (ctx.mem) Arguments(
|
1598
|
+
Argument* arg = new (ctx.mem) Argument(arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end, before_token)));
|
1599
|
+
Arguments* args = new (ctx.mem) Arguments(arg_pos);
|
1491
1600
|
*args << arg;
|
1492
|
-
return new (ctx.mem) Function_Call(
|
1601
|
+
return new (ctx.mem) Function_Call(call_pos, name, args);
|
1493
1602
|
}
|
1494
1603
|
|
1495
1604
|
Function_Call* Parser::parse_function_call()
|
1496
1605
|
{
|
1497
1606
|
lex< identifier >();
|
1498
1607
|
string name(Util::normalize_underscores(lexed));
|
1499
|
-
|
1608
|
+
ParserState source_position_of_call = pstate;
|
1500
1609
|
|
1501
|
-
Function_Call* the_call = new (ctx.mem) Function_Call(
|
1610
|
+
Function_Call* the_call = new (ctx.mem) Function_Call(source_position_of_call, name, parse_arguments());
|
1502
1611
|
return the_call;
|
1503
1612
|
}
|
1504
1613
|
|
1505
1614
|
Function_Call_Schema* Parser::parse_function_call_schema()
|
1506
1615
|
{
|
1507
1616
|
String* name = parse_identifier_schema();
|
1508
|
-
|
1617
|
+
ParserState source_position_of_call = pstate;
|
1509
1618
|
|
1510
|
-
Function_Call_Schema* the_call = new (ctx.mem) Function_Call_Schema(
|
1619
|
+
Function_Call_Schema* the_call = new (ctx.mem) Function_Call_Schema(source_position_of_call, name, parse_arguments());
|
1511
1620
|
return the_call;
|
1512
1621
|
}
|
1513
1622
|
|
1514
1623
|
If* Parser::parse_if_directive(bool else_if)
|
1515
1624
|
{
|
1516
1625
|
lex< if_directive >() || (else_if && lex< exactly<if_after_else_kwd> >());
|
1517
|
-
|
1626
|
+
ParserState if_source_position = pstate;
|
1518
1627
|
Expression* predicate = parse_list();
|
1519
1628
|
predicate->is_delayed(false);
|
1520
|
-
if (!peek< exactly<'{'> >()) error("expected '{' after the predicate for @if");
|
1629
|
+
if (!peek< exactly<'{'> >()) error("expected '{' after the predicate for @if", pstate);
|
1521
1630
|
Block* consequent = parse_block();
|
1522
1631
|
Block* alternative = 0;
|
1523
1632
|
if (lex< else_directive >()) {
|
1524
1633
|
if (peek< exactly<if_after_else_kwd> >()) {
|
1525
|
-
alternative = new (ctx.mem) Block(
|
1634
|
+
alternative = new (ctx.mem) Block(pstate);
|
1526
1635
|
(*alternative) << parse_if_directive(true);
|
1527
1636
|
}
|
1528
1637
|
else if (!peek< exactly<'{'> >()) {
|
1529
|
-
error("expected '{' after @else");
|
1638
|
+
error("expected '{' after @else", pstate);
|
1530
1639
|
}
|
1531
1640
|
else {
|
1532
1641
|
alternative = parse_block();
|
1533
1642
|
}
|
1534
1643
|
}
|
1535
|
-
return new (ctx.mem) If(
|
1644
|
+
return new (ctx.mem) If(if_source_position, predicate, consequent, alternative);
|
1536
1645
|
}
|
1537
1646
|
|
1538
1647
|
For* Parser::parse_for_directive()
|
1539
1648
|
{
|
1540
1649
|
lex< for_directive >();
|
1541
|
-
|
1542
|
-
if (!lex< variable >()) error("@for directive requires an iteration variable");
|
1650
|
+
ParserState for_source_position = pstate;
|
1651
|
+
if (!lex< variable >()) error("@for directive requires an iteration variable", pstate);
|
1543
1652
|
string var(Util::normalize_underscores(lexed));
|
1544
|
-
if (!lex< from >()) error("expected 'from' keyword in @for directive");
|
1653
|
+
if (!lex< from >()) error("expected 'from' keyword in @for directive", pstate);
|
1545
1654
|
Expression* lower_bound = parse_expression();
|
1546
1655
|
lower_bound->is_delayed(false);
|
1547
1656
|
bool inclusive = false;
|
1548
1657
|
if (lex< through >()) inclusive = true;
|
1549
1658
|
else if (lex< to >()) inclusive = false;
|
1550
|
-
else error("expected 'through' or 'to' keyword in @for directive");
|
1659
|
+
else error("expected 'through' or 'to' keyword in @for directive", pstate);
|
1551
1660
|
Expression* upper_bound = parse_expression();
|
1552
1661
|
upper_bound->is_delayed(false);
|
1553
|
-
if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @for directive");
|
1662
|
+
if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @for directive", pstate);
|
1554
1663
|
Block* body = parse_block();
|
1555
|
-
return new (ctx.mem) For(
|
1664
|
+
return new (ctx.mem) For(for_source_position, var, lower_bound, upper_bound, body, inclusive);
|
1556
1665
|
}
|
1557
1666
|
|
1558
1667
|
Each* Parser::parse_each_directive()
|
1559
1668
|
{
|
1560
1669
|
lex < each_directive >();
|
1561
|
-
|
1562
|
-
if (!lex< variable >()) error("@each directive requires an iteration variable");
|
1670
|
+
ParserState each_source_position = pstate;
|
1671
|
+
if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
|
1563
1672
|
vector<string> vars;
|
1564
1673
|
vars.push_back(Util::normalize_underscores(lexed));
|
1565
1674
|
while (peek< exactly<','> >() && lex< exactly<','> >()) {
|
1566
|
-
if (!lex< variable >()) error("@each directive requires an iteration variable");
|
1675
|
+
if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
|
1567
1676
|
vars.push_back(Util::normalize_underscores(lexed));
|
1568
1677
|
}
|
1569
|
-
if (!lex< in >()) error("expected 'in' keyword in @each directive");
|
1678
|
+
if (!lex< in >()) error("expected 'in' keyword in @each directive", pstate);
|
1570
1679
|
Expression* list = parse_list();
|
1571
1680
|
list->is_delayed(false);
|
1572
1681
|
if (list->concrete_type() == Expression::LIST) {
|
@@ -1575,39 +1684,43 @@ namespace Sass {
|
|
1575
1684
|
(*l)[i]->is_delayed(false);
|
1576
1685
|
}
|
1577
1686
|
}
|
1578
|
-
if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @each directive");
|
1687
|
+
if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @each directive", pstate);
|
1579
1688
|
Block* body = parse_block();
|
1580
|
-
return new (ctx.mem) Each(
|
1689
|
+
return new (ctx.mem) Each(each_source_position, vars, list, body);
|
1581
1690
|
}
|
1582
1691
|
|
1583
1692
|
While* Parser::parse_while_directive()
|
1584
1693
|
{
|
1585
1694
|
lex< while_directive >();
|
1586
|
-
|
1695
|
+
ParserState while_source_position = pstate;
|
1587
1696
|
Expression* predicate = parse_list();
|
1588
1697
|
predicate->is_delayed(false);
|
1589
1698
|
Block* body = parse_block();
|
1590
|
-
return new (ctx.mem) While(
|
1699
|
+
return new (ctx.mem) While(while_source_position, predicate, body);
|
1591
1700
|
}
|
1592
1701
|
|
1593
1702
|
Media_Block* Parser::parse_media_block()
|
1594
1703
|
{
|
1595
1704
|
lex< media >();
|
1596
|
-
|
1705
|
+
ParserState media_source_position = pstate;
|
1597
1706
|
|
1598
1707
|
List* media_queries = parse_media_queries();
|
1599
1708
|
|
1600
1709
|
if (!peek< exactly<'{'> >()) {
|
1601
|
-
error("expected '{' in media query");
|
1710
|
+
error("expected '{' in media query", pstate);
|
1602
1711
|
}
|
1603
|
-
|
1712
|
+
Media_Block* media_block = new (ctx.mem) Media_Block(media_source_position, media_queries, 0);
|
1713
|
+
Media_Block* prev_media_block = last_media_block;
|
1714
|
+
last_media_block = media_block;
|
1715
|
+
media_block->block(parse_block());
|
1716
|
+
last_media_block = prev_media_block;
|
1604
1717
|
|
1605
|
-
return
|
1718
|
+
return media_block;
|
1606
1719
|
}
|
1607
1720
|
|
1608
1721
|
List* Parser::parse_media_queries()
|
1609
1722
|
{
|
1610
|
-
List* media_queries = new (ctx.mem) List(
|
1723
|
+
List* media_queries = new (ctx.mem) List(pstate, 0, List::COMMA);
|
1611
1724
|
if (!peek< exactly<'{'> >()) (*media_queries) << parse_media_query();
|
1612
1725
|
while (lex< exactly<','> >()) (*media_queries) << parse_media_query();
|
1613
1726
|
return media_queries;
|
@@ -1616,17 +1729,24 @@ namespace Sass {
|
|
1616
1729
|
// Expression* Parser::parse_media_query()
|
1617
1730
|
Media_Query* Parser::parse_media_query()
|
1618
1731
|
{
|
1619
|
-
Media_Query* media_query = new (ctx.mem) Media_Query(
|
1732
|
+
Media_Query* media_query = new (ctx.mem) Media_Query(pstate);
|
1620
1733
|
|
1621
1734
|
if (lex< exactly< not_kwd > >()) media_query->is_negated(true);
|
1622
1735
|
else if (lex< exactly< only_kwd > >()) media_query->is_restricted(true);
|
1623
1736
|
|
1624
1737
|
if (peek< identifier_schema >()) media_query->media_type(parse_identifier_schema());
|
1625
|
-
else if (lex< identifier >()) media_query->media_type(
|
1738
|
+
else if (lex< identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
|
1626
1739
|
else (*media_query) << parse_media_expression();
|
1627
1740
|
|
1628
1741
|
while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
|
1629
|
-
|
1742
|
+
if (peek< identifier_schema >()) {
|
1743
|
+
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
|
1744
|
+
*schema << media_query->media_type();
|
1745
|
+
*schema << new (ctx.mem) String_Constant(pstate, " ");
|
1746
|
+
*schema << parse_identifier_schema();
|
1747
|
+
media_query->media_type(schema);
|
1748
|
+
}
|
1749
|
+
while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
|
1630
1750
|
return media_query;
|
1631
1751
|
}
|
1632
1752
|
|
@@ -1634,14 +1754,14 @@ namespace Sass {
|
|
1634
1754
|
{
|
1635
1755
|
if (peek< identifier_schema >()) {
|
1636
1756
|
String* ss = parse_identifier_schema();
|
1637
|
-
return new (ctx.mem) Media_Query_Expression(
|
1757
|
+
return new (ctx.mem) Media_Query_Expression(pstate, ss, 0, true);
|
1638
1758
|
}
|
1639
1759
|
if (!lex< exactly<'('> >()) {
|
1640
|
-
error("media query expression must begin with '('");
|
1760
|
+
error("media query expression must begin with '('", pstate);
|
1641
1761
|
}
|
1642
1762
|
Expression* feature = 0;
|
1643
1763
|
if (peek< exactly<')'> >()) {
|
1644
|
-
error("media feature required in media query expression");
|
1764
|
+
error("media feature required in media query expression", pstate);
|
1645
1765
|
}
|
1646
1766
|
feature = parse_expression();
|
1647
1767
|
Expression* expression = 0;
|
@@ -1649,36 +1769,36 @@ namespace Sass {
|
|
1649
1769
|
expression = parse_list();
|
1650
1770
|
}
|
1651
1771
|
if (!lex< exactly<')'> >()) {
|
1652
|
-
error("unclosed parenthesis in media query expression");
|
1772
|
+
error("unclosed parenthesis in media query expression", pstate);
|
1653
1773
|
}
|
1654
|
-
return new (ctx.mem) Media_Query_Expression(
|
1774
|
+
return new (ctx.mem) Media_Query_Expression(feature->pstate(), feature, expression);
|
1655
1775
|
}
|
1656
1776
|
|
1657
1777
|
Feature_Block* Parser::parse_feature_block()
|
1658
1778
|
{
|
1659
1779
|
lex< supports >();
|
1660
|
-
|
1780
|
+
ParserState supports_source_position = pstate;
|
1661
1781
|
|
1662
1782
|
Feature_Query* feature_queries = parse_feature_queries();
|
1663
1783
|
|
1664
1784
|
if (!peek< exactly<'{'> >()) {
|
1665
|
-
error("expected '{' in feature query");
|
1785
|
+
error("expected '{' in feature query", pstate);
|
1666
1786
|
}
|
1667
1787
|
Block* block = parse_block();
|
1668
1788
|
|
1669
|
-
return new (ctx.mem) Feature_Block(
|
1789
|
+
return new (ctx.mem) Feature_Block(supports_source_position, feature_queries, block);
|
1670
1790
|
}
|
1671
1791
|
|
1672
1792
|
Feature_Query* Parser::parse_feature_queries()
|
1673
1793
|
{
|
1674
|
-
Feature_Query* fq = new (ctx.mem) Feature_Query(
|
1675
|
-
Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(
|
1794
|
+
Feature_Query* fq = new (ctx.mem) Feature_Query(pstate);
|
1795
|
+
Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
|
1676
1796
|
cond->is_root(true);
|
1677
1797
|
while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
|
1678
1798
|
(*cond) << parse_feature_query();
|
1679
1799
|
(*fq) << cond;
|
1680
1800
|
|
1681
|
-
if (fq->empty()) error("expected @supports condition (e.g. (display: flexbox))");
|
1801
|
+
if (fq->empty()) error("expected @supports condition (e.g. (display: flexbox))", pstate);
|
1682
1802
|
|
1683
1803
|
return fq;
|
1684
1804
|
}
|
@@ -1694,12 +1814,12 @@ namespace Sass {
|
|
1694
1814
|
|
1695
1815
|
Feature_Query_Condition* Parser::parse_feature_query_in_parens()
|
1696
1816
|
{
|
1697
|
-
Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(
|
1817
|
+
Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
|
1698
1818
|
|
1699
|
-
if (!lex< exactly<'('> >()) error("@supports declaration expected '('");
|
1819
|
+
if (!lex< exactly<'('> >()) error("@supports declaration expected '('", pstate);
|
1700
1820
|
while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
|
1701
1821
|
(*cond) << parse_feature_query();
|
1702
|
-
if (!lex< exactly<')'> >()) error("unclosed parenthesis in @supports declaration");
|
1822
|
+
if (!lex< exactly<')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
|
1703
1823
|
|
1704
1824
|
return (cond->length() == 1) ? (*cond)[0] : cond;
|
1705
1825
|
}
|
@@ -1737,19 +1857,71 @@ namespace Sass {
|
|
1737
1857
|
Feature_Query_Condition* Parser::parse_supports_declaration()
|
1738
1858
|
{
|
1739
1859
|
Declaration* declaration = parse_declaration();
|
1740
|
-
Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(declaration->
|
1741
|
-
declaration->position(),
|
1860
|
+
Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(declaration->pstate(),
|
1742
1861
|
1,
|
1743
1862
|
declaration->property(),
|
1744
1863
|
declaration->value());
|
1745
1864
|
return cond;
|
1746
1865
|
}
|
1747
1866
|
|
1867
|
+
At_Root_Block* Parser::parse_at_root_block()
|
1868
|
+
{
|
1869
|
+
lex<at_root>();
|
1870
|
+
ParserState at_source_position = pstate;
|
1871
|
+
Block* body = 0;
|
1872
|
+
At_Root_Expression* expr = 0;
|
1873
|
+
Selector_Lookahead lookahead_result;
|
1874
|
+
in_at_root = true;
|
1875
|
+
if (peek< exactly<'('> >()) {
|
1876
|
+
expr = parse_at_root_expression();
|
1877
|
+
body = parse_block();
|
1878
|
+
}
|
1879
|
+
else if (peek< exactly<'{'> >()) {
|
1880
|
+
body = parse_block();
|
1881
|
+
}
|
1882
|
+
else if ((lookahead_result = lookahead_for_selector(position)).found) {
|
1883
|
+
Ruleset* r = parse_ruleset(lookahead_result);
|
1884
|
+
body = new (ctx.mem) Block(r->pstate(), 1);
|
1885
|
+
*body << r;
|
1886
|
+
}
|
1887
|
+
in_at_root = false;
|
1888
|
+
At_Root_Block* at_root = new (ctx.mem) At_Root_Block(at_source_position, body);
|
1889
|
+
if (expr) at_root->expression(expr);
|
1890
|
+
return at_root;
|
1891
|
+
}
|
1892
|
+
|
1893
|
+
At_Root_Expression* Parser::parse_at_root_expression()
|
1894
|
+
{
|
1895
|
+
lex< exactly<'('> >();
|
1896
|
+
if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
|
1897
|
+
|
1898
|
+
if (!peek< alternatives< with_directive, without_directive > >()) {
|
1899
|
+
const char* i = position;
|
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);
|
1903
|
+
}
|
1904
|
+
|
1905
|
+
Declaration* declaration = parse_declaration();
|
1906
|
+
List* value = new (ctx.mem) List(declaration->value()->pstate(), 1);
|
1907
|
+
|
1908
|
+
if (declaration->value()->concrete_type() == Expression::LIST) {
|
1909
|
+
value = static_cast<List*>(declaration->value());
|
1910
|
+
}
|
1911
|
+
else *value << declaration->value();
|
1912
|
+
|
1913
|
+
At_Root_Expression* cond = new (ctx.mem) At_Root_Expression(declaration->pstate(),
|
1914
|
+
declaration->property(),
|
1915
|
+
value);
|
1916
|
+
if (!lex< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
|
1917
|
+
return cond;
|
1918
|
+
}
|
1919
|
+
|
1748
1920
|
At_Rule* Parser::parse_at_rule()
|
1749
1921
|
{
|
1750
1922
|
lex<at_keyword>();
|
1751
1923
|
string kwd(lexed);
|
1752
|
-
|
1924
|
+
ParserState at_source_position = pstate;
|
1753
1925
|
Selector* sel = 0;
|
1754
1926
|
Expression* val = 0;
|
1755
1927
|
Selector_Lookahead lookahead = lookahead_for_extension_target(position);
|
@@ -1766,7 +1938,7 @@ namespace Sass {
|
|
1766
1938
|
}
|
1767
1939
|
Block* body = 0;
|
1768
1940
|
if (peek< exactly<'{'> >()) body = parse_block();
|
1769
|
-
At_Rule* rule = new (ctx.mem) At_Rule(
|
1941
|
+
At_Rule* rule = new (ctx.mem) At_Rule(at_source_position, kwd, sel, body);
|
1770
1942
|
if (!sel) rule->value(val);
|
1771
1943
|
return rule;
|
1772
1944
|
}
|
@@ -1774,19 +1946,19 @@ namespace Sass {
|
|
1774
1946
|
Warning* Parser::parse_warning()
|
1775
1947
|
{
|
1776
1948
|
lex< warn >();
|
1777
|
-
return new (ctx.mem) Warning(
|
1949
|
+
return new (ctx.mem) Warning(pstate, parse_list());
|
1778
1950
|
}
|
1779
1951
|
|
1780
1952
|
Error* Parser::parse_error()
|
1781
1953
|
{
|
1782
1954
|
lex< err >();
|
1783
|
-
return new (ctx.mem) Error(
|
1955
|
+
return new (ctx.mem) Error(pstate, parse_list());
|
1784
1956
|
}
|
1785
1957
|
|
1786
1958
|
Debug* Parser::parse_debug()
|
1787
1959
|
{
|
1788
1960
|
lex< dbg >();
|
1789
|
-
return new (ctx.mem) Debug(
|
1961
|
+
return new (ctx.mem) Debug(pstate, parse_list());
|
1790
1962
|
}
|
1791
1963
|
|
1792
1964
|
Selector_Lookahead Parser::lookahead_for_selector(const char* start)
|
@@ -1805,7 +1977,7 @@ namespace Sass {
|
|
1805
1977
|
(q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
|
1806
1978
|
(q = peek< percentage >(p)) ||
|
1807
1979
|
(q = peek< dimension >(p)) ||
|
1808
|
-
(q = peek<
|
1980
|
+
(q = peek< quoted_string >(p)) ||
|
1809
1981
|
(q = peek< exactly<'*'> >(p)) ||
|
1810
1982
|
(q = peek< exactly<'('> >(p)) ||
|
1811
1983
|
(q = peek< exactly<')'> >(p)) ||
|
@@ -1815,6 +1987,7 @@ namespace Sass {
|
|
1815
1987
|
(q = peek< exactly<'~'> >(p)) ||
|
1816
1988
|
(q = peek< exactly<'>'> >(p)) ||
|
1817
1989
|
(q = peek< exactly<','> >(p)) ||
|
1990
|
+
(saw_stuff && (q = peek< exactly<'-'> >(p))) ||
|
1818
1991
|
(q = peek< binomial >(p)) ||
|
1819
1992
|
(q = peek< sequence< optional<sign>,
|
1820
1993
|
optional<digits>,
|
@@ -1863,7 +2036,7 @@ namespace Sass {
|
|
1863
2036
|
(q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
|
1864
2037
|
(q = peek< percentage >(p)) ||
|
1865
2038
|
(q = peek< dimension >(p)) ||
|
1866
|
-
(q = peek<
|
2039
|
+
(q = peek< quoted_string >(p)) ||
|
1867
2040
|
(q = peek< exactly<'*'> >(p)) ||
|
1868
2041
|
(q = peek< exactly<'('> >(p)) ||
|
1869
2042
|
(q = peek< exactly<')'> >(p)) ||
|
@@ -1873,6 +2046,7 @@ namespace Sass {
|
|
1873
2046
|
(q = peek< exactly<'~'> >(p)) ||
|
1874
2047
|
(q = peek< exactly<'>'> >(p)) ||
|
1875
2048
|
(q = peek< exactly<','> >(p)) ||
|
2049
|
+
(saw_stuff && (q = peek< exactly<'-'> >(p))) ||
|
1876
2050
|
(q = peek< binomial >(p)) ||
|
1877
2051
|
(q = peek< sequence< optional<sign>,
|
1878
2052
|
optional<digits>,
|
@@ -1961,7 +2135,7 @@ namespace Sass {
|
|
1961
2135
|
encoding = "GB-18030";
|
1962
2136
|
break;
|
1963
2137
|
}
|
1964
|
-
if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding);
|
2138
|
+
if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding, pstate);
|
1965
2139
|
position += skip;
|
1966
2140
|
}
|
1967
2141
|
|
@@ -1979,7 +2153,7 @@ namespace Sass {
|
|
1979
2153
|
Expression* Parser::fold_operands(Expression* base, vector<Expression*>& operands, Binary_Expression::Type op)
|
1980
2154
|
{
|
1981
2155
|
for (size_t i = 0, S = operands.size(); i < S; ++i) {
|
1982
|
-
base = new (ctx.mem) Binary_Expression(
|
2156
|
+
base = new (ctx.mem) Binary_Expression(pstate, op, base, operands[i]);
|
1983
2157
|
Binary_Expression* b = static_cast<Binary_Expression*>(base);
|
1984
2158
|
if (op == Binary_Expression::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
1985
2159
|
base->is_delayed(true);
|
@@ -1995,7 +2169,7 @@ namespace Sass {
|
|
1995
2169
|
Expression* Parser::fold_operands(Expression* base, vector<Expression*>& operands, vector<Binary_Expression::Type>& ops)
|
1996
2170
|
{
|
1997
2171
|
for (size_t i = 0, S = operands.size(); i < S; ++i) {
|
1998
|
-
base = new (ctx.mem) Binary_Expression(
|
2172
|
+
base = new (ctx.mem) Binary_Expression(base->pstate(), ops[i], base, operands[i]);
|
1999
2173
|
Binary_Expression* b = static_cast<Binary_Expression*>(base);
|
2000
2174
|
if (ops[i] == Binary_Expression::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
2001
2175
|
base->is_delayed(true);
|
@@ -2010,7 +2184,7 @@ namespace Sass {
|
|
2010
2184
|
|
2011
2185
|
void Parser::error(string msg, Position pos)
|
2012
2186
|
{
|
2013
|
-
throw Sass_Error(Sass_Error::syntax, path, pos.line ? pos :
|
2187
|
+
throw Sass_Error(Sass_Error::syntax, ParserState(path, pos.line ? pos : before_token, Offset(0, 0)), msg);
|
2014
2188
|
}
|
2015
2189
|
|
2016
2190
|
}
|