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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/ext/libsass/.gitignore +13 -6
  4. data/ext/libsass/Makefile +42 -26
  5. data/ext/libsass/Makefile.am +43 -30
  6. data/ext/libsass/Readme.md +4 -2
  7. data/ext/libsass/appveyor.yml +10 -14
  8. data/ext/libsass/ast.cpp +54 -44
  9. data/ext/libsass/ast.hpp +404 -236
  10. data/ext/libsass/ast_def_macros.hpp +5 -0
  11. data/ext/libsass/ast_factory.hpp +6 -3
  12. data/ext/libsass/ast_fwd_decl.hpp +12 -0
  13. data/ext/libsass/b64/encode.h +2 -2
  14. data/ext/libsass/backtrace.hpp +13 -17
  15. data/ext/libsass/base64vlq.hpp +4 -1
  16. data/ext/libsass/bind.cpp +12 -15
  17. data/ext/libsass/bind.hpp +6 -6
  18. data/ext/libsass/color_names.hpp +4 -1
  19. data/ext/libsass/configure.ac +7 -21
  20. data/ext/libsass/constants.cpp +6 -4
  21. data/ext/libsass/constants.hpp +10 -4
  22. data/ext/libsass/context.cpp +89 -58
  23. data/ext/libsass/context.hpp +28 -35
  24. data/ext/libsass/contextualize.cpp +20 -10
  25. data/ext/libsass/contextualize.hpp +8 -23
  26. data/ext/libsass/contrib/libsass.spec +66 -0
  27. data/ext/libsass/cssize.cpp +547 -0
  28. data/ext/libsass/cssize.hpp +82 -0
  29. data/ext/libsass/debug.hpp +3 -3
  30. data/ext/libsass/debugger.hpp +358 -0
  31. data/ext/libsass/emitter.cpp +255 -0
  32. data/ext/libsass/emitter.hpp +83 -0
  33. data/ext/libsass/environment.hpp +7 -3
  34. data/ext/libsass/error_handling.cpp +11 -14
  35. data/ext/libsass/error_handling.hpp +9 -7
  36. data/ext/libsass/eval.cpp +253 -161
  37. data/ext/libsass/eval.hpp +13 -13
  38. data/ext/libsass/expand.cpp +135 -64
  39. data/ext/libsass/expand.hpp +11 -13
  40. data/ext/libsass/extend.cpp +66 -20
  41. data/ext/libsass/extend.hpp +6 -11
  42. data/ext/libsass/file.cpp +31 -26
  43. data/ext/libsass/file.hpp +6 -1
  44. data/ext/libsass/functions.cpp +270 -287
  45. data/ext/libsass/functions.hpp +8 -11
  46. data/ext/libsass/inspect.cpp +385 -255
  47. data/ext/libsass/inspect.hpp +15 -26
  48. data/ext/libsass/kwd_arg_macros.hpp +5 -0
  49. data/ext/libsass/mapping.hpp +4 -3
  50. data/ext/libsass/memory_manager.hpp +5 -2
  51. data/ext/libsass/node.cpp +50 -50
  52. data/ext/libsass/node.hpp +26 -27
  53. data/ext/libsass/operation.hpp +15 -4
  54. data/ext/libsass/output.cpp +401 -0
  55. data/ext/libsass/output.hpp +56 -0
  56. data/ext/libsass/parser.cpp +573 -399
  57. data/ext/libsass/parser.hpp +122 -88
  58. data/ext/libsass/paths.hpp +7 -2
  59. data/ext/libsass/plugins.cpp +155 -0
  60. data/ext/libsass/plugins.hpp +56 -0
  61. data/ext/libsass/position.cpp +128 -0
  62. data/ext/libsass/position.hpp +108 -11
  63. data/ext/libsass/prelexer.cpp +184 -110
  64. data/ext/libsass/prelexer.hpp +131 -24
  65. data/ext/libsass/remove_placeholders.cpp +1 -1
  66. data/ext/libsass/remove_placeholders.hpp +6 -6
  67. data/ext/libsass/sass.cpp +3 -3
  68. data/ext/libsass/sass.h +12 -4
  69. data/ext/libsass/sass2scss.cpp +3 -2
  70. data/ext/libsass/sass2scss.h +5 -0
  71. data/ext/libsass/sass_context.cpp +136 -37
  72. data/ext/libsass/sass_context.h +19 -10
  73. data/ext/libsass/sass_functions.cpp +29 -2
  74. data/ext/libsass/sass_functions.h +8 -2
  75. data/ext/libsass/sass_interface.cpp +32 -23
  76. data/ext/libsass/sass_interface.h +9 -4
  77. data/ext/libsass/sass_util.cpp +19 -23
  78. data/ext/libsass/sass_util.hpp +28 -27
  79. data/ext/libsass/sass_values.cpp +6 -4
  80. data/ext/libsass/sass_values.h +3 -3
  81. data/ext/libsass/script/ci-build-libsass +13 -1
  82. data/ext/libsass/script/ci-report-coverage +2 -1
  83. data/ext/libsass/source_map.cpp +79 -28
  84. data/ext/libsass/source_map.hpp +35 -16
  85. data/ext/libsass/subset_map.hpp +6 -4
  86. data/ext/libsass/to_c.hpp +4 -4
  87. data/ext/libsass/to_string.cpp +13 -8
  88. data/ext/libsass/to_string.hpp +6 -4
  89. data/ext/libsass/units.cpp +2 -1
  90. data/ext/libsass/units.hpp +6 -1
  91. data/ext/libsass/utf8_string.cpp +0 -5
  92. data/ext/libsass/utf8_string.hpp +3 -2
  93. data/ext/libsass/util.cpp +461 -49
  94. data/ext/libsass/util.hpp +34 -13
  95. data/ext/libsass/version.sh +10 -0
  96. data/ext/libsass/win/libsass.filters +20 -11
  97. data/ext/libsass/win/libsass.vcxproj +11 -8
  98. data/lib/sassc/importer.rb +1 -8
  99. data/lib/sassc/native.rb +7 -0
  100. data/lib/sassc/native/native_context_api.rb +5 -5
  101. data/lib/sassc/version.rb +1 -1
  102. data/test/native_test.rb +1 -1
  103. metadata +14 -10
  104. data/ext/libsass/copy_c_str.cpp +0 -13
  105. data/ext/libsass/copy_c_str.hpp +0 -5
  106. data/ext/libsass/output_compressed.cpp +0 -401
  107. data/ext/libsass/output_compressed.hpp +0 -95
  108. data/ext/libsass/output_nested.cpp +0 -364
  109. data/ext/libsass/output_nested.hpp +0 -108
  110. data/ext/libsass/test-driver +0 -127
  111. data/ext/libsass/token.hpp +0 -32
@@ -0,0 +1,255 @@
1
+ #include "util.hpp"
2
+ #include "context.hpp"
3
+ #include "output.hpp"
4
+ #include "emitter.hpp"
5
+ #include "utf8_string.hpp"
6
+
7
+ namespace Sass {
8
+ using namespace std;
9
+
10
+ Emitter::Emitter(Context* ctx)
11
+ : wbuf(),
12
+ ctx(ctx),
13
+ indentation(0),
14
+ scheduled_space(0),
15
+ scheduled_linefeed(0),
16
+ scheduled_delimiter(false),
17
+ in_comment(false),
18
+ in_at_rule(false),
19
+ in_media_block(false),
20
+ in_declaration(false),
21
+ in_declaration_list(false)
22
+ { }
23
+
24
+ // return buffer as string
25
+ string Emitter::get_buffer(void)
26
+ {
27
+ return wbuf.buffer;
28
+ }
29
+
30
+ Output_Style Emitter::output_style(void)
31
+ {
32
+ return ctx ? ctx->output_style : COMPRESSED;
33
+ }
34
+
35
+ // PROXY METHODS FOR SOURCE MAPS
36
+
37
+ void Emitter::add_source_index(size_t idx)
38
+ { wbuf.smap.source_index.push_back(idx); }
39
+
40
+ string Emitter::generate_source_map(Context &ctx)
41
+ { return wbuf.smap.generate_source_map(ctx); }
42
+
43
+ void Emitter::set_filename(const string& str)
44
+ { wbuf.smap.file = str; }
45
+
46
+ void Emitter::add_open_mapping(AST_Node* node)
47
+ { wbuf.smap.add_open_mapping(node); }
48
+ void Emitter::add_close_mapping(AST_Node* node)
49
+ { wbuf.smap.add_close_mapping(node); }
50
+ ParserState Emitter::remap(const ParserState& pstate)
51
+ { return wbuf.smap.remap(pstate); }
52
+
53
+ // MAIN BUFFER MANIPULATION
54
+
55
+ // add outstanding delimiter
56
+ void Emitter::finalize(void)
57
+ {
58
+ scheduled_space = 0;
59
+ if (scheduled_linefeed)
60
+ scheduled_linefeed = 1;
61
+ flush_schedules();
62
+ }
63
+
64
+ // flush scheduled space/linefeed
65
+ void Emitter::flush_schedules(void)
66
+ {
67
+ // check the schedule
68
+ if (scheduled_linefeed) {
69
+ string linefeeds = "";
70
+
71
+ for (size_t i = 0; i < scheduled_linefeed; i++)
72
+ linefeeds += ctx ? ctx->linefeed : "\n";
73
+ scheduled_space = 0;
74
+ scheduled_linefeed = 0;
75
+ append_string(linefeeds);
76
+
77
+ } else if (scheduled_space) {
78
+ string spaces(scheduled_space, ' ');
79
+ scheduled_space = 0;
80
+ append_string(spaces);
81
+ }
82
+ if (scheduled_delimiter) {
83
+ scheduled_delimiter = false;
84
+ append_string(";");
85
+ }
86
+ }
87
+
88
+ // prepend some text or token to the buffer
89
+ void Emitter::prepend_output(const OutputBuffer& output)
90
+ {
91
+ wbuf.smap.prepend(output);
92
+ wbuf.buffer = output.buffer + wbuf.buffer;
93
+ }
94
+
95
+ // prepend some text or token to the buffer
96
+ void Emitter::prepend_string(const string& text)
97
+ {
98
+ wbuf.smap.prepend(Offset(text));
99
+ wbuf.buffer = text + wbuf.buffer;
100
+ }
101
+
102
+ // append some text or token to the buffer
103
+ void Emitter::append_string(const string& text)
104
+ {
105
+ // write space/lf
106
+ flush_schedules();
107
+
108
+ if (in_comment && output_style() == COMPACT) {
109
+ // unescape comment nodes
110
+ string out = comment_to_string(text);
111
+ // add to buffer
112
+ wbuf.buffer += out;
113
+ // account for data in source-maps
114
+ wbuf.smap.append(Offset(out));
115
+ } else {
116
+ // add to buffer
117
+ wbuf.buffer += text;
118
+ // account for data in source-maps
119
+ wbuf.smap.append(Offset(text));
120
+ }
121
+ }
122
+
123
+ // append some white-space only text
124
+ void Emitter::append_wspace(const string& text)
125
+ {
126
+ if (text.empty()) return;
127
+ if (peek_linefeed(text.c_str())) {
128
+ scheduled_space = 0;
129
+ append_mandatory_linefeed();
130
+ }
131
+ }
132
+
133
+ // append some text or token to the buffer
134
+ // this adds source-mappings for node start and end
135
+ void Emitter::append_token(const string& text, AST_Node* node)
136
+ {
137
+ flush_schedules();
138
+ add_open_mapping(node);
139
+ append_string(text);
140
+ add_close_mapping(node);
141
+ }
142
+
143
+ // HELPER METHODS
144
+
145
+ void Emitter::append_indentation()
146
+ {
147
+ if (output_style() == COMPRESSED) return;
148
+ if (output_style() == COMPACT) return;
149
+ if (scheduled_linefeed && indentation)
150
+ scheduled_linefeed = 1;
151
+ string indent = "";
152
+ for (size_t i = 0; i < indentation; i++)
153
+ indent += ctx ? ctx->indent : " ";
154
+ append_string(indent);
155
+ }
156
+
157
+ void Emitter::append_delimiter()
158
+ {
159
+ scheduled_delimiter = true;
160
+ if (output_style() == COMPACT) {
161
+ if (indentation == 0) {
162
+ append_mandatory_linefeed();
163
+ } else {
164
+ append_mandatory_space();
165
+ }
166
+ } else if (output_style() != COMPRESSED) {
167
+ append_optional_linefeed();
168
+ }
169
+ }
170
+
171
+ void Emitter::append_comma_separator()
172
+ {
173
+ scheduled_space = 0;
174
+ append_string(",");
175
+ append_optional_space();
176
+ }
177
+
178
+ void Emitter::append_colon_separator()
179
+ {
180
+ scheduled_space = 0;
181
+ append_string(":");
182
+ append_optional_space();
183
+ }
184
+
185
+ void Emitter::append_mandatory_space()
186
+ {
187
+ scheduled_space = 1;
188
+ }
189
+
190
+ void Emitter::append_optional_space()
191
+ {
192
+ if (output_style() != COMPRESSED && buffer().size()) {
193
+ char lst = buffer().at(buffer().length() - 1);
194
+ if (!isspace(lst)) append_mandatory_space();
195
+ }
196
+ }
197
+
198
+ void Emitter::append_special_linefeed()
199
+ {
200
+ if (output_style() == COMPACT) {
201
+ append_mandatory_linefeed();
202
+ for (size_t p = 0; p < indentation; p++)
203
+ append_string(ctx ? ctx->indent : " ");
204
+ }
205
+ }
206
+
207
+ void Emitter::append_optional_linefeed()
208
+ {
209
+ if (output_style() == COMPACT) {
210
+ append_mandatory_space();
211
+ } else {
212
+ append_mandatory_linefeed();
213
+ }
214
+ }
215
+
216
+ void Emitter::append_mandatory_linefeed()
217
+ {
218
+ if (output_style() != COMPRESSED) {
219
+ scheduled_linefeed = 1;
220
+ scheduled_space = 0;
221
+ // flush_schedules();
222
+ }
223
+ }
224
+
225
+ void Emitter::append_scope_opener(AST_Node* node)
226
+ {
227
+ append_optional_space();
228
+ flush_schedules();
229
+ if (node) add_open_mapping(node);
230
+ append_string("{");
231
+ append_optional_linefeed();
232
+ // append_optional_space();
233
+ ++ indentation;
234
+ }
235
+ void Emitter::append_scope_closer(AST_Node* node)
236
+ {
237
+ -- indentation;
238
+ scheduled_linefeed = 0;
239
+ if (output_style() == COMPRESSED)
240
+ scheduled_delimiter = false;
241
+ if (output_style() == EXPANDED) {
242
+ append_optional_linefeed();
243
+ append_indentation();
244
+ } else {
245
+ append_optional_space();
246
+ }
247
+ append_string("}");
248
+ if (node) add_close_mapping(node);
249
+ append_optional_linefeed();
250
+ if (indentation != 0) return;
251
+ if (output_style() != COMPRESSED)
252
+ scheduled_linefeed = 2;
253
+ }
254
+
255
+ }
@@ -0,0 +1,83 @@
1
+ #ifndef SASS_EMITTER_H
2
+ #define SASS_EMITTER_H
3
+
4
+ #include <string>
5
+ #include "source_map.hpp"
6
+ #include "ast_fwd_decl.hpp"
7
+
8
+ namespace Sass {
9
+ class Context;
10
+ using namespace std;
11
+
12
+ class Emitter {
13
+
14
+ public:
15
+ Emitter(Context* ctx);
16
+ virtual ~Emitter() { };
17
+
18
+ protected:
19
+ OutputBuffer wbuf;
20
+ public:
21
+ const string buffer(void) { return wbuf.buffer; }
22
+ const SourceMap smap(void) { return wbuf.smap; }
23
+ const OutputBuffer output(void) { return wbuf; }
24
+ // proxy methods for source maps
25
+ void add_source_index(size_t idx);
26
+ void set_filename(const string& str);
27
+ void add_open_mapping(AST_Node* node);
28
+ void add_close_mapping(AST_Node* node);
29
+ string generate_source_map(Context &ctx);
30
+ ParserState remap(const ParserState& pstate);
31
+
32
+ public:
33
+ Context* ctx;
34
+ size_t indentation;
35
+ size_t scheduled_space;
36
+ size_t scheduled_linefeed;
37
+ bool scheduled_delimiter;
38
+
39
+ public:
40
+ bool in_comment;
41
+ bool in_at_rule;
42
+ bool in_media_block;
43
+ bool in_declaration;
44
+ bool in_declaration_list;
45
+
46
+ public:
47
+ // return buffer as string
48
+ string get_buffer(void);
49
+ // flush scheduled space/linefeed
50
+ Output_Style output_style(void);
51
+ // add outstanding linefeed
52
+ void finalize(void);
53
+ // flush scheduled space/linefeed
54
+ void flush_schedules(void);
55
+ // prepend some text or token to the buffer
56
+ void prepend_string(const string& text);
57
+ void prepend_output(const OutputBuffer& out);
58
+ // append some text or token to the buffer
59
+ void append_string(const string& text);
60
+ // append some white-space only text
61
+ void append_wspace(const string& text);
62
+ // append some text or token to the buffer
63
+ // this adds source-mappings for node start and end
64
+ void append_token(const string& text, AST_Node* node);
65
+
66
+ public: // syntax sugar
67
+ void append_indentation();
68
+ void append_optional_space(void);
69
+ void append_mandatory_space(void);
70
+ void append_special_linefeed(void);
71
+ void append_optional_linefeed(void);
72
+ void append_mandatory_linefeed(void);
73
+ void append_scope_opener(AST_Node* node = 0);
74
+ void append_scope_closer(AST_Node* node = 0);
75
+ void append_comma_separator(void);
76
+ void append_colon_separator(void);
77
+ void append_delimiter(void);
78
+
79
+ };
80
+
81
+ }
82
+
83
+ #endif
@@ -1,10 +1,12 @@
1
- #define SASS_ENVIRONMENT
1
+ #ifndef SASS_ENVIRONMENT_H
2
+ #define SASS_ENVIRONMENT_H
2
3
 
3
- #include <string>
4
4
  #include <map>
5
- #include "ast_def_macros.hpp"
5
+ #include <string>
6
6
  #include <iostream>
7
7
 
8
+ #include "ast_def_macros.hpp"
9
+
8
10
  namespace Sass {
9
11
  using std::string;
10
12
  using std::map;
@@ -73,3 +75,5 @@ namespace Sass {
73
75
  }
74
76
  };
75
77
  }
78
+
79
+ #endif
@@ -1,28 +1,25 @@
1
- #ifndef SASS_ERROR_HANDLING
2
- #include "error_handling.hpp"
3
- #endif
4
-
5
- #include "backtrace.hpp"
6
1
  #include "prelexer.hpp"
2
+ #include "backtrace.hpp"
3
+ #include "error_handling.hpp"
7
4
 
8
5
  namespace Sass {
9
6
 
10
- Sass_Error::Sass_Error(Type type, string path, Position position, string message)
11
- : type(type), path(path), position(position), message(message)
7
+ Sass_Error::Sass_Error(Type type, ParserState pstate, string message)
8
+ : type(type), pstate(pstate), message(message)
12
9
  { }
13
10
 
14
- void error(string msg, string path, Position position)
15
- { throw Sass_Error(Sass_Error::syntax, path, position, msg); }
11
+ void error(string msg, ParserState pstate)
12
+ { throw Sass_Error(Sass_Error::syntax, pstate, msg); }
16
13
 
17
- void error(string msg, string path, Position position, Backtrace* bt)
14
+ void error(string msg, ParserState pstate, Backtrace* bt)
18
15
  {
19
- if (!path.empty() && Prelexer::string_constant(path.c_str()))
20
- path = path.substr(1, path.size() - 1);
16
+ if (!pstate.path.empty() && Prelexer::quoted_string(pstate.path.c_str()))
17
+ pstate.path = pstate.path.substr(1, pstate.path.size() - 1);
21
18
 
22
- Backtrace top(bt, path, position, "");
19
+ Backtrace top(bt, pstate, "");
23
20
  msg += top.to_string();
24
21
 
25
- throw Sass_Error(Sass_Error::syntax, path, position, msg);
22
+ throw Sass_Error(Sass_Error::syntax, pstate, msg);
26
23
  }
27
24
 
28
25
  }
@@ -1,9 +1,9 @@
1
- #define SASS_ERROR_HANDLING
1
+ #ifndef SASS_ERROR_HANDLING_H
2
+ #define SASS_ERROR_HANDLING_H
3
+
2
4
  #include <string>
3
5
 
4
- #ifndef SASS_POSITION
5
6
  #include "position.hpp"
6
- #endif
7
7
 
8
8
  namespace Sass {
9
9
  using namespace std;
@@ -15,14 +15,16 @@ namespace Sass {
15
15
 
16
16
  Type type;
17
17
  string path;
18
- Position position;
18
+ ParserState pstate;
19
19
  string message;
20
20
 
21
- Sass_Error(Type type, string path, Position position, string message);
21
+ Sass_Error(Type type, ParserState pstate, string message);
22
22
 
23
23
  };
24
24
 
25
- void error(string msg, string path, Position position);
26
- void error(string msg, string path, Position position, Backtrace* bt);
25
+ void error(string msg, ParserState pstate);
26
+ void error(string msg, ParserState pstate, Backtrace* bt);
27
27
 
28
28
  }
29
+
30
+ #endif
@@ -9,6 +9,7 @@
9
9
  #include "context.hpp"
10
10
  #include "backtrace.hpp"
11
11
  #include "prelexer.hpp"
12
+ #include "parser.hpp"
12
13
 
13
14
  #include <cstdlib>
14
15
  #include <cmath>
@@ -81,16 +82,16 @@ namespace Sass {
81
82
  string variable(f->variable());
82
83
  Expression* low = f->lower_bound()->perform(this);
83
84
  if (low->concrete_type() != Expression::NUMBER) {
84
- error("lower bound of `@for` directive must be numeric", low->path(), low->position());
85
+ error("lower bound of `@for` directive must be numeric", low->pstate());
85
86
  }
86
87
  Expression* high = f->upper_bound()->perform(this);
87
88
  if (high->concrete_type() != Expression::NUMBER) {
88
- error("upper bound of `@for` directive must be numeric", high->path(), high->position());
89
+ error("upper bound of `@for` directive must be numeric", high->pstate());
89
90
  }
90
91
  double start = static_cast<Number*>(low)->value();
91
92
  double end = static_cast<Number*>(high)->value();
92
93
  Env new_env;
93
- new_env[variable] = new (ctx.mem) Number(low->path(), low->position(), start);
94
+ new_env[variable] = new (ctx.mem) Number(low->pstate(), start);
94
95
  new_env.link(env);
95
96
  env = &new_env;
96
97
  Block* body = f->block();
@@ -99,7 +100,7 @@ namespace Sass {
99
100
  if (f->is_inclusive()) ++end;
100
101
  for (double i = start;
101
102
  i < end;
102
- (*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), ++i)) {
103
+ (*env)[variable] = new (ctx.mem) Number(low->pstate(), ++i)) {
103
104
  val = body->perform(this);
104
105
  if (val) break;
105
106
  }
@@ -107,7 +108,7 @@ namespace Sass {
107
108
  if (f->is_inclusive()) --end;
108
109
  for (double i = start;
109
110
  i > end;
110
- (*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), --i)) {
111
+ (*env)[variable] = new (ctx.mem) Number(low->pstate(), --i)) {
111
112
  val = body->perform(this);
112
113
  if (val) break;
113
114
  }
@@ -126,7 +127,7 @@ namespace Sass {
126
127
  map = static_cast<Map*>(expr);
127
128
  }
128
129
  else if (expr->concrete_type() != Expression::LIST) {
129
- list = new (ctx.mem) List(expr->path(), expr->position(), 1, List::COMMA);
130
+ list = new (ctx.mem) List(expr->pstate(), 1, List::COMMA);
130
131
  *list << expr;
131
132
  }
132
133
  else {
@@ -144,7 +145,7 @@ namespace Sass {
144
145
  Expression* value = map->at(key);
145
146
 
146
147
  if (variables.size() == 1) {
147
- List* variable = new (ctx.mem) List(map->path(), map->position(), 2, List::SPACE);
148
+ List* variable = new (ctx.mem) List(map->pstate(), 2, List::SPACE);
148
149
  *variable << key;
149
150
  *variable << value;
150
151
  (*env)[variables[0]] = variable;
@@ -161,7 +162,7 @@ namespace Sass {
161
162
  for (size_t i = 0, L = list->length(); i < L; ++i) {
162
163
  List* variable = 0;
163
164
  if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
164
- variable = new (ctx.mem) List((*list)[i]->path(), (*list)[i]->position(), 1, List::COMMA);
165
+ variable = new (ctx.mem) List((*list)[i]->pstate(), 1, List::COMMA);
165
166
  *variable << (*list)[i];
166
167
  }
167
168
  else {
@@ -172,7 +173,7 @@ namespace Sass {
172
173
  (*env)[variables[j]] = (*variable)[j];
173
174
  }
174
175
  else {
175
- (*env)[variables[j]] = new (ctx.mem) Null(expr->path(), expr->position());
176
+ (*env)[variables[j]] = new (ctx.mem) Null(expr->pstate());
176
177
  }
177
178
  val = body->perform(this);
178
179
  if (val) break;
@@ -203,7 +204,7 @@ namespace Sass {
203
204
  Expression* Eval::operator()(Warning* w)
204
205
  {
205
206
  Expression* message = w->message()->perform(this);
206
- To_String to_string;
207
+ To_String to_string(&ctx);
207
208
 
208
209
  // try to use generic function
209
210
  if (env->has("@warn[f]")) {
@@ -224,7 +225,7 @@ namespace Sass {
224
225
  }
225
226
 
226
227
  string result(unquote(message->perform(&to_string)));
227
- Backtrace top(backtrace, w->path(), w->position(), "");
228
+ Backtrace top(backtrace, w->pstate(), "");
228
229
  cerr << "WARNING: " << result;
229
230
  cerr << top.to_string(true);
230
231
  cerr << endl << endl;
@@ -234,7 +235,7 @@ namespace Sass {
234
235
  Expression* Eval::operator()(Error* e)
235
236
  {
236
237
  Expression* message = e->message()->perform(this);
237
- To_String to_string;
238
+ To_String to_string(&ctx);
238
239
 
239
240
  // try to use generic function
240
241
  if (env->has("@error[f]")) {
@@ -255,7 +256,7 @@ namespace Sass {
255
256
  }
256
257
 
257
258
  string result(unquote(message->perform(&to_string)));
258
- Backtrace top(backtrace, e->path(), e->position(), "");
259
+ Backtrace top(backtrace, e->pstate(), "");
259
260
  cerr << "Error: " << result;
260
261
  cerr << top.to_string(true);
261
262
  cerr << endl << endl;
@@ -265,7 +266,7 @@ namespace Sass {
265
266
  Expression* Eval::operator()(Debug* d)
266
267
  {
267
268
  Expression* message = d->value()->perform(this);
268
- To_String to_string;
269
+ To_String to_string(&ctx);
269
270
 
270
271
  // try to use generic function
271
272
  if (env->has("@debug[f]")) {
@@ -287,8 +288,8 @@ namespace Sass {
287
288
 
288
289
  string cwd(ctx.get_cwd());
289
290
  string result(unquote(message->perform(&to_string)));
290
- string rel_path(Sass::File::resolve_relative_path(d->path(), cwd, cwd));
291
- cerr << rel_path << ":" << d->position().line << ":" << " DEBUG: " << result;
291
+ string rel_path(Sass::File::resolve_relative_path(d->pstate().path, cwd, cwd));
292
+ cerr << rel_path << ":" << d->pstate().line << ":" << " DEBUG: " << result;
292
293
  cerr << endl;
293
294
  return 0;
294
295
  }
@@ -296,8 +297,7 @@ namespace Sass {
296
297
  Expression* Eval::operator()(List* l)
297
298
  {
298
299
  if (l->is_expanded()) return l;
299
- List* ll = new (ctx.mem) List(l->path(),
300
- l->position(),
300
+ List* ll = new (ctx.mem) List(l->pstate(),
301
301
  l->length(),
302
302
  l->separator(),
303
303
  l->is_arglist());
@@ -311,8 +311,7 @@ namespace Sass {
311
311
  Expression* Eval::operator()(Map* m)
312
312
  {
313
313
  if (m->is_expanded()) return m;
314
- Map* mm = new (ctx.mem) Map(m->path(),
315
- m->position(),
314
+ Map* mm = new (ctx.mem) Map(m->pstate(),
316
315
  m->length());
317
316
  for (auto key : m->keys()) {
318
317
  *mm << std::make_pair(key->perform(this), m->at(key)->perform(this));
@@ -337,9 +336,10 @@ namespace Sass {
337
336
  // don't eval delayed expressions (the '/' when used as a separator)
338
337
  if (op_type == Binary_Expression::DIV && b->is_delayed()) return b;
339
338
  // if one of the operands is a '/' then make sure it's evaluated
340
- if (typeid(*b->left()) == typeid(Binary_Expression)) b->left()->is_delayed(false);
341
- // the logical connectives need to short-circuit
342
339
  Expression* lhs = b->left()->perform(this);
340
+ lhs->is_delayed(false);
341
+ while (typeid(*lhs) == typeid(Binary_Expression)) lhs = lhs->perform(this);
342
+
343
343
  switch (op_type) {
344
344
  case Binary_Expression::AND:
345
345
  return *lhs ? b->right()->perform(this) : lhs;
@@ -354,15 +354,17 @@ namespace Sass {
354
354
  }
355
355
  // not a logical connective, so go ahead and eval the rhs
356
356
  Expression* rhs = b->right()->perform(this);
357
+ rhs->is_delayed(false);
358
+ while (typeid(*rhs) == typeid(Binary_Expression)) rhs = rhs->perform(this);
357
359
 
358
360
  // see if it's a relational expression
359
361
  switch(op_type) {
360
- case Binary_Expression::EQ: return new (ctx.mem) Boolean(b->path(), b->position(), eq(lhs, rhs, ctx));
361
- case Binary_Expression::NEQ: return new (ctx.mem) Boolean(b->path(), b->position(), !eq(lhs, rhs, ctx));
362
- case Binary_Expression::GT: return new (ctx.mem) Boolean(b->path(), b->position(), !lt(lhs, rhs, ctx) && !eq(lhs, rhs, ctx));
363
- case Binary_Expression::GTE: return new (ctx.mem) Boolean(b->path(), b->position(), !lt(lhs, rhs, ctx));
364
- case Binary_Expression::LT: return new (ctx.mem) Boolean(b->path(), b->position(), lt(lhs, rhs, ctx));
365
- case Binary_Expression::LTE: return new (ctx.mem) Boolean(b->path(), b->position(), lt(lhs, rhs, ctx) || eq(lhs, rhs, ctx));
362
+ case Binary_Expression::EQ: return new (ctx.mem) Boolean(b->pstate(), eq(lhs, rhs, ctx));
363
+ case Binary_Expression::NEQ: return new (ctx.mem) Boolean(b->pstate(), !eq(lhs, rhs, ctx));
364
+ case Binary_Expression::GT: return new (ctx.mem) Boolean(b->pstate(), !lt(lhs, rhs, ctx) && !eq(lhs, rhs, ctx));
365
+ case Binary_Expression::GTE: return new (ctx.mem) Boolean(b->pstate(), !lt(lhs, rhs, ctx));
366
+ case Binary_Expression::LT: return new (ctx.mem) Boolean(b->pstate(), lt(lhs, rhs, ctx));
367
+ case Binary_Expression::LTE: return new (ctx.mem) Boolean(b->pstate(), lt(lhs, rhs, ctx) || eq(lhs, rhs, ctx));
366
368
 
367
369
  default: break;
368
370
  }
@@ -382,14 +384,25 @@ namespace Sass {
382
384
  if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
383
385
  return op_colors(ctx, op_type, lhs, rhs);
384
386
  }
385
- return op_strings(ctx, op_type, lhs, rhs);
387
+
388
+ Expression* ex = op_strings(ctx, op_type, lhs, rhs);
389
+ if (String_Constant* str = (String_Constant*) ex)
390
+ {
391
+ if (str->concrete_type() != Expression::STRING) return ex;
392
+ String_Constant* lstr = dynamic_cast<String_Constant*>(lhs);
393
+ String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
394
+ if (String_Constant* org = lstr ? lstr : rstr)
395
+ { str->quote_mark(org->quote_mark()); }
396
+ }
397
+ return ex;
398
+
386
399
  }
387
400
 
388
401
  Expression* Eval::operator()(Unary_Expression* u)
389
402
  {
390
403
  Expression* operand = u->operand()->perform(this);
391
404
  if (u->type() == Unary_Expression::NOT) {
392
- Boolean* result = new (ctx.mem) Boolean(u->path(), u->position(), (bool)*operand);
405
+ Boolean* result = new (ctx.mem) Boolean(u->pstate(), (bool)*operand);
393
406
  result->value(!result->value());
394
407
  return result;
395
408
  }
@@ -401,15 +414,14 @@ namespace Sass {
401
414
  return result;
402
415
  }
403
416
  else {
404
- To_String to_string;
417
+ To_String to_string(&ctx);
405
418
  // Special cases: +/- variables which evaluate to null ouput just +/-,
406
419
  // but +/- null itself outputs the string
407
420
  if (operand->concrete_type() == Expression::NULL_VAL && typeid(*(u->operand())) == typeid(Variable)) {
408
- u->operand(new (ctx.mem) String_Constant(u->path(), u->position(), ""));
421
+ u->operand(new (ctx.mem) String_Constant(u->pstate(), ""));
409
422
  }
410
423
  else u->operand(operand);
411
- String_Constant* result = new (ctx.mem) String_Constant(u->path(),
412
- u->position(),
424
+ String_Constant* result = new (ctx.mem) String_Constant(u->pstate(),
413
425
  u->perform(&to_string));
414
426
  return result;
415
427
  }
@@ -434,13 +446,11 @@ namespace Sass {
434
446
 
435
447
  // if it doesn't exist, just pass it through as a literal
436
448
  if (!env->has(full_name)) {
437
- Function_Call* lit = new (ctx.mem) Function_Call(c->path(),
438
- c->position(),
449
+ Function_Call* lit = new (ctx.mem) Function_Call(c->pstate(),
439
450
  c->name(),
440
451
  args);
441
- To_String to_string;
442
- return new (ctx.mem) String_Constant(c->path(),
443
- c->position(),
452
+ To_String to_string(&ctx);
453
+ return new (ctx.mem) String_Constant(c->pstate(),
444
454
  lit->perform(&to_string));
445
455
  }
446
456
 
@@ -473,12 +483,12 @@ namespace Sass {
473
483
  Env* old_env = env;
474
484
  env = &new_env;
475
485
 
476
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
486
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
477
487
  backtrace = &here;
478
488
 
479
489
  result = body->perform(this);
480
490
  if (!result) {
481
- error(string("function ") + c->name() + " did not return a value", c->path(), c->position());
491
+ error(string("function ") + c->name() + " did not return a value", c->pstate());
482
492
  }
483
493
  backtrace = here.parent;
484
494
  env = old_env;
@@ -490,10 +500,10 @@ namespace Sass {
490
500
  Env* old_env = env;
491
501
  env = &new_env;
492
502
 
493
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
503
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
494
504
  backtrace = &here;
495
505
 
496
- result = func(*env, *old_env, ctx, def->signature(), c->path(), c->position(), backtrace);
506
+ result = func(*env, *old_env, ctx, def->signature(), c->pstate(), backtrace);
497
507
 
498
508
  backtrace = here.parent;
499
509
  env = old_env;
@@ -502,9 +512,9 @@ namespace Sass {
502
512
  else if (c_func) {
503
513
 
504
514
  if (full_name == "*[f]") {
505
- String_Constant *str = new (ctx.mem) String_Constant(c->path(), c->position(), c->name());
506
- Arguments* new_args = new (ctx.mem) Arguments(c->path(), c->position());
507
- *new_args << new (ctx.mem) Argument(c->path(), c->position(), str);
515
+ String_Constant *str = new (ctx.mem) String_Constant(c->pstate(), c->name());
516
+ Arguments* new_args = new (ctx.mem) Arguments(c->pstate());
517
+ *new_args << new (ctx.mem) Argument(c->pstate(), str);
508
518
  *new_args += args;
509
519
  args = new_args;
510
520
  }
@@ -514,7 +524,7 @@ namespace Sass {
514
524
  Env* old_env = env;
515
525
  env = &new_env;
516
526
 
517
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
527
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
518
528
  backtrace = &here;
519
529
 
520
530
  To_C to_c;
@@ -527,11 +537,11 @@ namespace Sass {
527
537
  }
528
538
  Sass_Value* c_val = c_func(c_args, def->cookie());
529
539
  if (sass_value_get_tag(c_val) == SASS_ERROR) {
530
- error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->path(), c->position(), backtrace);
540
+ error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), backtrace);
531
541
  } else if (sass_value_get_tag(c_val) == SASS_WARNING) {
532
- error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->path(), c->position(), backtrace);
542
+ error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), backtrace);
533
543
  }
534
- result = cval_to_astnode(c_val, ctx, backtrace, c->path(), c->position());
544
+ result = cval_to_astnode(c_val, ctx, backtrace, c->pstate());
535
545
 
536
546
  backtrace = here.parent;
537
547
  sass_delete_value(c_args);
@@ -545,7 +555,7 @@ namespace Sass {
545
555
  stringstream ss;
546
556
  ss << full_name << arity;
547
557
  string resolved_name(ss.str());
548
- if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->path(), c->position());
558
+ if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->pstate());
549
559
  Definition* resolved_def = static_cast<Definition*>((*env)[resolved_name]);
550
560
  params = resolved_def->parameters();
551
561
  Env newer_env;
@@ -554,10 +564,10 @@ namespace Sass {
554
564
  Env* old_env = env;
555
565
  env = &newer_env;
556
566
 
557
- Backtrace here(backtrace, c->path(), c->position(), ", in function `" + c->name() + "`");
567
+ Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
558
568
  backtrace = &here;
559
569
 
560
- result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->path(), c->position(), backtrace);
570
+ result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->pstate(), backtrace);
561
571
 
562
572
  backtrace = here.parent;
563
573
  env = old_env;
@@ -565,7 +575,17 @@ namespace Sass {
565
575
 
566
576
  // backtrace = here.parent;
567
577
  // env = old_env;
568
- result->position(c->position());
578
+
579
+
580
+ // link back to function definition
581
+ // only do this for custom functions
582
+ if (result->pstate().file == string::npos)
583
+ result->pstate(c->pstate());
584
+
585
+ do {
586
+ result->is_delayed(result->concrete_type() == Expression::STRING);
587
+ result = result->perform(this);
588
+ } while (result->concrete_type() == Expression::NONE);
569
589
  return result;
570
590
  }
571
591
 
@@ -573,35 +593,47 @@ namespace Sass {
573
593
  {
574
594
  Expression* evaluated_name = s->name()->perform(this);
575
595
  Expression* evaluated_args = s->arguments()->perform(this);
576
- String_Schema* ss = new (ctx.mem) String_Schema(s->path(), s->position(), 2);
596
+ String_Schema* ss = new (ctx.mem) String_Schema(s->pstate(), 2);
577
597
  (*ss) << evaluated_name << evaluated_args;
578
598
  return ss->perform(this);
579
599
  }
580
600
 
581
601
  Expression* Eval::operator()(Variable* v)
582
602
  {
583
- To_String to_string;
603
+ To_String to_string(&ctx);
584
604
  string name(v->name());
585
605
  Expression* value = 0;
586
606
  if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
587
- else error("unbound variable " + v->name(), v->path(), v->position());
607
+ else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
588
608
  // cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << endl;
589
609
  if (typeid(*value) == typeid(Argument)) value = static_cast<Argument*>(value)->value();
590
610
 
591
611
  // behave according to as ruby sass (add leading zero)
592
612
  if (value->concrete_type() == Expression::NUMBER) {
593
- Number* n = static_cast<Number*>(value);
594
- value = new (ctx.mem) Number(n->path(),
595
- n->position(),
596
- n->value(),
597
- n->unit(),
598
- true);
613
+ value = new (ctx.mem) Number(*static_cast<Number*>(value));
614
+ static_cast<Number*>(value)->zero(true);
599
615
  }
600
616
  else if (value->concrete_type() == Expression::STRING) {
601
- String_Constant* s = static_cast<String_Constant*>(value);
602
- value = new (ctx.mem) String_Constant(s->path(),
603
- s->position(),
604
- s->value());
617
+ if (auto str = dynamic_cast<String_Quoted*>(value)) {
618
+ value = new (ctx.mem) String_Quoted(*str);
619
+ } else if (auto str = dynamic_cast<String_Constant*>(value)) {
620
+ value = new (ctx.mem) String_Constant(*str);
621
+ }
622
+ }
623
+ else if (value->concrete_type() == Expression::LIST) {
624
+ value = new (ctx.mem) List(*static_cast<List*>(value));
625
+ }
626
+ else if (value->concrete_type() == Expression::MAP) {
627
+ value = new (ctx.mem) Map(*static_cast<Map*>(value));
628
+ }
629
+ else if (value->concrete_type() == Expression::BOOLEAN) {
630
+ value = new (ctx.mem) Boolean(*static_cast<Boolean*>(value));
631
+ }
632
+ else if (value->concrete_type() == Expression::COLOR) {
633
+ value = new (ctx.mem) Color(*static_cast<Color*>(value));
634
+ }
635
+ else if (value->concrete_type() == Expression::NULL_VAL) {
636
+ value = new (ctx.mem) Null(value->pstate());
605
637
  }
606
638
 
607
639
  // cerr << "\ttype is now: " << typeid(*value).name() << endl << endl;
@@ -625,24 +657,21 @@ namespace Sass {
625
657
  switch (t->type())
626
658
  {
627
659
  case Textual::NUMBER:
628
- result = new (ctx.mem) Number(t->path(),
629
- t->position(),
630
- atof(num.c_str()),
660
+ result = new (ctx.mem) Number(t->pstate(),
661
+ sass_atof(num.c_str()),
631
662
  "",
632
663
  zero);
633
664
  break;
634
665
  case Textual::PERCENTAGE:
635
- result = new (ctx.mem) Number(t->path(),
636
- t->position(),
637
- atof(num.c_str()),
666
+ result = new (ctx.mem) Number(t->pstate(),
667
+ sass_atof(num.c_str()),
638
668
  "%",
639
669
  zero);
640
670
  break;
641
671
  case Textual::DIMENSION:
642
- result = new (ctx.mem) Number(t->path(),
643
- t->position(),
644
- atof(num.c_str()),
645
- Token(number(text.c_str())),
672
+ result = new (ctx.mem) Number(t->pstate(),
673
+ sass_atof(num.c_str()),
674
+ Token(number(text.c_str()), t->pstate()),
646
675
  zero);
647
676
  break;
648
677
  case Textual::HEX: {
@@ -651,8 +680,7 @@ namespace Sass {
651
680
  string r(hext.substr(0,2));
652
681
  string g(hext.substr(2,2));
653
682
  string b(hext.substr(4,2));
654
- result = new (ctx.mem) Color(t->path(),
655
- t->position(),
683
+ result = new (ctx.mem) Color(t->pstate(),
656
684
  static_cast<double>(strtol(r.c_str(), NULL, 16)),
657
685
  static_cast<double>(strtol(g.c_str(), NULL, 16)),
658
686
  static_cast<double>(strtol(b.c_str(), NULL, 16)),
@@ -660,8 +688,7 @@ namespace Sass {
660
688
  t->value());
661
689
  }
662
690
  else {
663
- result = new (ctx.mem) Color(t->path(),
664
- t->position(),
691
+ result = new (ctx.mem) Color(t->pstate(),
665
692
  static_cast<double>(strtol(string(2,hext[0]).c_str(), NULL, 16)),
666
693
  static_cast<double>(strtol(string(2,hext[1]).c_str(), NULL, 16)),
667
694
  static_cast<double>(strtol(string(2,hext[2]).c_str(), NULL, 16)),
@@ -676,8 +703,7 @@ namespace Sass {
676
703
  Expression* Eval::operator()(Number* n)
677
704
  {
678
705
  // behave according to as ruby sass (add leading zero)
679
- return new (ctx.mem) Number(n->path(),
680
- n->position(),
706
+ return new (ctx.mem) Number(n->pstate(),
681
707
  n->value(),
682
708
  n->unit(),
683
709
  true);
@@ -700,32 +726,93 @@ namespace Sass {
700
726
  }
701
727
  }
702
728
 
729
+ string Eval::interpolation(Expression* s) {
730
+
731
+ if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
732
+
733
+ if (str_quoted->quote_mark()) {
734
+ return string_escape(str_quoted->value());
735
+ } else {
736
+ return evacuate_escapes(str_quoted->value());
737
+ }
738
+
739
+ } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
740
+
741
+ return evacuate_escapes(str_constant->value());
742
+
743
+ } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
744
+
745
+ string res = "";
746
+ for(auto i : str_schema->elements())
747
+ res += (interpolation(i));
748
+ //ToDo: do this in one step
749
+ auto esc = evacuate_escapes(res);
750
+ auto unq = unquote(esc);
751
+ if (unq == esc) {
752
+ return string_to_output(res);
753
+ } else {
754
+ return evacuate_quotes(unq);
755
+ }
756
+
757
+ } else if (List* list = dynamic_cast<List*>(s)) {
758
+
759
+ string acc = ""; // ToDo: different output styles
760
+ string sep = list->separator() == List::Separator::COMMA ? "," : " ";
761
+ if (ctx.output_style != COMPRESSED && sep == ",") sep += " ";
762
+ bool initial = false;
763
+ for(auto item : list->elements()) {
764
+ if (initial) acc += sep;
765
+ acc += interpolation(item);
766
+ initial = true;
767
+ }
768
+ return evacuate_quotes(acc);
769
+
770
+ } else if (Variable* var = dynamic_cast<Variable*>(s)) {
771
+
772
+ string name(var->name());
773
+ if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate());
774
+ Expression* value = static_cast<Expression*>((*env)[name]);
775
+ return evacuate_quotes(interpolation(value));
776
+
777
+ } else if (Binary_Expression* var = dynamic_cast<Binary_Expression*>(s)) {
778
+
779
+ Expression* ex = operator()(var);
780
+ return evacuate_quotes(interpolation(ex));
781
+
782
+ } else if (Function_Call* var = dynamic_cast<Function_Call*>(s)) {
783
+
784
+ Expression* ex = operator()(var);
785
+ return evacuate_quotes(interpolation(ex));
786
+
787
+ } else {
788
+
789
+ To_String to_string(&ctx);
790
+ // to_string.in_decl_list = true;
791
+ return evacuate_quotes(s->perform(&to_string));
792
+
793
+ }
794
+ }
795
+
703
796
  Expression* Eval::operator()(String_Schema* s)
704
797
  {
705
798
  string acc;
706
- ctx._skip_source_map_update = true;
707
- To_String to_string(&ctx);
708
- ctx._skip_source_map_update = false;
709
799
  for (size_t i = 0, L = s->length(); i < L; ++i) {
710
- string chunk((*s)[i]->perform(this)->perform(&to_string));
711
- if (((s->quote_mark() && is_quoted(chunk)) || !s->quote_mark()) && (*s)[i]->is_interpolant()) { // some redundancy in that test
712
- acc += unquote(chunk);
713
- }
714
- else {
715
- acc += chunk;
716
- }
800
+ acc += interpolation((*s)[i]);
717
801
  }
718
- return new (ctx.mem) String_Constant(s->path(),
719
- s->position(),
720
- acc);
802
+ String_Quoted* str = new (ctx.mem) String_Quoted(s->pstate(), acc);
803
+ if (!str->quote_mark()) {
804
+ str->value(string_unescape(str->value()));
805
+ } else if (str->quote_mark()) {
806
+ str->quote_mark('*');
807
+ }
808
+ return str;
721
809
  }
722
810
 
723
811
  Expression* Eval::operator()(String_Constant* s)
724
812
  {
725
- if (!s->is_delayed() && ctx.names_to_colors.count(s->value())) {
813
+ if (!s->quote_mark() && !s->is_delayed() && ctx.names_to_colors.count(s->value())) {
726
814
  Color* c = new (ctx.mem) Color(*ctx.names_to_colors[s->value()]);
727
- c->path(s->path());
728
- c->position(s->position());
815
+ c->pstate(s->pstate());
729
816
  c->disp(s->value());
730
817
  return c;
731
818
  }
@@ -734,8 +821,7 @@ namespace Sass {
734
821
 
735
822
  Expression* Eval::operator()(Feature_Query* q)
736
823
  {
737
- Feature_Query* qq = new (ctx.mem) Feature_Query(q->path(),
738
- q->position(),
824
+ Feature_Query* qq = new (ctx.mem) Feature_Query(q->pstate(),
739
825
  q->length());
740
826
  for (size_t i = 0, L = q->length(); i < L; ++i) {
741
827
  *qq << static_cast<Feature_Query_Condition*>((*q)[i]->perform(this));
@@ -748,8 +834,7 @@ namespace Sass {
748
834
  String* feature = c->feature();
749
835
  Expression* value = c->value();
750
836
  value = (value ? value->perform(this) : 0);
751
- Feature_Query_Condition* cc = new (ctx.mem) Feature_Query_Condition(c->path(),
752
- c->position(),
837
+ Feature_Query_Condition* cc = new (ctx.mem) Feature_Query_Condition(c->pstate(),
753
838
  c->length(),
754
839
  feature,
755
840
  value,
@@ -761,12 +846,25 @@ namespace Sass {
761
846
  return cc;
762
847
  }
763
848
 
849
+ Expression* Eval::operator()(At_Root_Expression* e)
850
+ {
851
+ Expression* feature = e->feature();
852
+ feature = (feature ? feature->perform(this) : 0);
853
+ Expression* value = e->value();
854
+ value = (value ? value->perform(this) : 0);
855
+ Expression* ee = new (ctx.mem) At_Root_Expression(e->pstate(),
856
+ static_cast<String*>(feature),
857
+ value,
858
+ e->is_interpolated());
859
+ return ee;
860
+ }
861
+
764
862
  Expression* Eval::operator()(Media_Query* q)
765
863
  {
864
+ To_String to_string(&ctx);
766
865
  String* t = q->media_type();
767
866
  t = static_cast<String*>(t ? t->perform(this) : 0);
768
- Media_Query* qq = new (ctx.mem) Media_Query(q->path(),
769
- q->position(),
867
+ Media_Query* qq = new (ctx.mem) Media_Query(q->pstate(),
770
868
  t,
771
869
  q->length(),
772
870
  q->is_negated(),
@@ -783,8 +881,7 @@ namespace Sass {
783
881
  feature = (feature ? feature->perform(this) : 0);
784
882
  Expression* value = e->value();
785
883
  value = (value ? value->perform(this) : 0);
786
- return new (ctx.mem) Media_Query_Expression(e->path(),
787
- e->position(),
884
+ return new (ctx.mem) Media_Query_Expression(e->pstate(),
788
885
  feature,
789
886
  value,
790
887
  e->is_interpolated());
@@ -812,8 +909,7 @@ namespace Sass {
812
909
  }
813
910
  else
814
911
  if(val->concrete_type() != Expression::LIST) {
815
- List* wrapper = new (ctx.mem) List(val->path(),
816
- val->position(),
912
+ List* wrapper = new (ctx.mem) List(val->pstate(),
817
913
  0,
818
914
  List::COMMA,
819
915
  true);
@@ -821,8 +917,7 @@ namespace Sass {
821
917
  val = wrapper;
822
918
  }
823
919
  }
824
- return new (ctx.mem) Argument(a->path(),
825
- a->position(),
920
+ return new (ctx.mem) Argument(a->pstate(),
826
921
  val,
827
922
  a->name(),
828
923
  is_rest_argument,
@@ -831,13 +926,18 @@ namespace Sass {
831
926
 
832
927
  Expression* Eval::operator()(Arguments* a)
833
928
  {
834
- Arguments* aa = new (ctx.mem) Arguments(a->path(), a->position());
929
+ Arguments* aa = new (ctx.mem) Arguments(a->pstate());
835
930
  for (size_t i = 0, L = a->length(); i < L; ++i) {
836
931
  *aa << static_cast<Argument*>((*a)[i]->perform(this));
837
932
  }
838
933
  return aa;
839
934
  }
840
935
 
936
+ Expression* Eval::operator()(Comment* c)
937
+ {
938
+ return 0;
939
+ }
940
+
841
941
  inline Expression* Eval::fallback_impl(AST_Node* n)
842
942
  {
843
943
  return static_cast<Expression*>(n);
@@ -913,7 +1013,7 @@ namespace Sass {
913
1013
  {
914
1014
  if (lhs->concrete_type() != Expression::NUMBER ||
915
1015
  rhs->concrete_type() != Expression::NUMBER)
916
- error("may only compare numbers", lhs->path(), lhs->position());
1016
+ error("may only compare numbers", lhs->pstate());
917
1017
  Number* l = static_cast<Number*>(lhs);
918
1018
  Number* r = static_cast<Number*>(rhs);
919
1019
  Number tmp_r(*r);
@@ -921,7 +1021,7 @@ namespace Sass {
921
1021
  string l_unit(l->unit());
922
1022
  string r_unit(tmp_r.unit());
923
1023
  if (!l_unit.empty() && !r_unit.empty() && l->unit() != tmp_r.unit()) {
924
- error("cannot compare numbers with incompatible units", l->path(), l->position());
1024
+ error("cannot compare numbers with incompatible units", l->pstate());
925
1025
  }
926
1026
  return l->value() < tmp_r.value();
927
1027
  }
@@ -934,10 +1034,10 @@ namespace Sass {
934
1034
  double rv = r->value();
935
1035
  Binary_Expression::Type op = b->type();
936
1036
  if (op == Binary_Expression::DIV && !rv) {
937
- return new (ctx.mem) String_Constant(l->path(), b->position(), "Infinity");
1037
+ return new (ctx.mem) String_Constant(l->pstate(), "Infinity");
938
1038
  }
939
1039
  if (op == Binary_Expression::MOD && !rv) {
940
- error("division by zero", r->path(), r->position());
1040
+ error("division by zero", r->pstate());
941
1041
  }
942
1042
 
943
1043
  Number tmp(*r);
@@ -946,10 +1046,10 @@ namespace Sass {
946
1046
  string r_unit(tmp.unit());
947
1047
  if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&
948
1048
  (op == Binary_Expression::ADD || op == Binary_Expression::SUB)) {
949
- error("cannot add or subtract numbers with incompatible units", l->path(), l->position());
1049
+ error("Incompatible units: '"+r_unit+"' and '"+l_unit+"'.", l->pstate());
950
1050
  }
951
1051
  Number* v = new (ctx.mem) Number(*l);
952
- v->position(b->position());
1052
+ v->pstate(b->pstate());
953
1053
  if (l_unit.empty() && (op == Binary_Expression::ADD || op == Binary_Expression::SUB || op == Binary_Expression::MOD)) {
954
1054
  v->numerator_units() = r->numerator_units();
955
1055
  v->denominator_units() = r->denominator_units();
@@ -988,8 +1088,7 @@ namespace Sass {
988
1088
  switch (op) {
989
1089
  case Binary_Expression::ADD:
990
1090
  case Binary_Expression::MUL: {
991
- return new (ctx.mem) Color(l->path(),
992
- l->position(),
1091
+ return new (ctx.mem) Color(l->pstate(),
993
1092
  ops[op](lv, r->r()),
994
1093
  ops[op](lv, r->g()),
995
1094
  ops[op](lv, r->b()),
@@ -998,17 +1097,17 @@ namespace Sass {
998
1097
  case Binary_Expression::SUB:
999
1098
  case Binary_Expression::DIV: {
1000
1099
  string sep(op == Binary_Expression::SUB ? "-" : "/");
1001
- To_String to_string;
1002
- string color(r->sixtuplet() ? r->perform(&to_string) :
1100
+ To_String to_string(&ctx);
1101
+ string color(r->sixtuplet() && (ctx.output_style != COMPRESSED) ?
1102
+ r->perform(&to_string) :
1003
1103
  Util::normalize_sixtuplet(r->perform(&to_string)));
1004
- return new (ctx.mem) String_Constant(l->path(),
1005
- l->position(),
1104
+ return new (ctx.mem) String_Constant(l->pstate(),
1006
1105
  l->perform(&to_string)
1007
1106
  + sep
1008
1107
  + color);
1009
1108
  } break;
1010
1109
  case Binary_Expression::MOD: {
1011
- error("cannot divide a number by a color", r->path(), r->position());
1110
+ error("cannot divide a number by a color", r->pstate());
1012
1111
  } break;
1013
1112
  default: break; // caller should ensure that we don't get here
1014
1113
  }
@@ -1021,9 +1120,8 @@ namespace Sass {
1021
1120
  Color* l = static_cast<Color*>(lhs);
1022
1121
  Number* r = static_cast<Number*>(rhs);
1023
1122
  double rv = r->value();
1024
- if (op == Binary_Expression::DIV && !rv) error("division by zero", r->path(), r->position());
1025
- return new (ctx.mem) Color(l->path(),
1026
- l->position(),
1123
+ if (op == Binary_Expression::DIV && !rv) error("division by zero", r->pstate());
1124
+ return new (ctx.mem) Color(l->pstate(),
1027
1125
  ops[op](l->r(), rv),
1028
1126
  ops[op](l->g(), rv),
1029
1127
  ops[op](l->b(), rv),
@@ -1035,14 +1133,13 @@ namespace Sass {
1035
1133
  Color* l = static_cast<Color*>(lhs);
1036
1134
  Color* r = static_cast<Color*>(rhs);
1037
1135
  if (l->a() != r->a()) {
1038
- error("alpha channels must be equal when combining colors", r->path(), r->position());
1136
+ error("alpha channels must be equal when combining colors", r->pstate());
1039
1137
  }
1040
1138
  if ((op == Binary_Expression::DIV || op == Binary_Expression::MOD) &&
1041
1139
  (!r->r() || !r->g() ||!r->b())) {
1042
- error("division by zero", r->path(), r->position());
1140
+ error("division by zero", r->pstate());
1043
1141
  }
1044
- return new (ctx.mem) Color(l->path(),
1045
- l->position(),
1142
+ return new (ctx.mem) Color(l->pstate(),
1046
1143
  ops[op](l->r(), r->r()),
1047
1144
  ops[op](l->g(), r->g()),
1048
1145
  ops[op](l->b(), r->b()),
@@ -1051,20 +1148,18 @@ namespace Sass {
1051
1148
 
1052
1149
  Expression* op_strings(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression*rhs)
1053
1150
  {
1054
- To_String to_string;
1151
+ To_String to_string(&ctx);
1055
1152
  Expression::Concrete_Type ltype = lhs->concrete_type();
1056
1153
  Expression::Concrete_Type rtype = rhs->concrete_type();
1057
1154
 
1058
1155
  string lstr(lhs->perform(&to_string));
1059
1156
  string rstr(rhs->perform(&to_string));
1060
1157
 
1061
- bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->needs_unquoting();
1062
- bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->needs_unquoting();
1158
+ bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->sass_fix_1291();
1159
+ bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->sass_fix_1291();
1063
1160
  bool l_str_color = ltype == Expression::STRING && ctx.names_to_colors.count(lstr) && !l_str_quoted;
1064
1161
  bool r_str_color = rtype == Expression::STRING && ctx.names_to_colors.count(rstr) && !r_str_quoted;
1065
1162
 
1066
- bool unquoted = false;
1067
- if (ltype == Expression::STRING && lstr[0] != '"' && lstr[0] != '\'') unquoted = true;
1068
1163
  if (l_str_color && r_str_color) {
1069
1164
  return op_colors(ctx, op, ctx.names_to_colors[lstr], ctx.names_to_colors[rstr]);
1070
1165
  }
@@ -1080,67 +1175,64 @@ namespace Sass {
1080
1175
  else if (ltype == Expression::NUMBER && r_str_color) {
1081
1176
  return op_number_color(ctx, op, lhs, ctx.names_to_colors[rstr]);
1082
1177
  }
1083
- if (op == Binary_Expression::MUL) error("invalid operands for multiplication", lhs->path(), lhs->position());
1084
- if (op == Binary_Expression::MOD) error("invalid operands for modulo", lhs->path(), lhs->position());
1178
+ if (op == Binary_Expression::MUL) error("invalid operands for multiplication", lhs->pstate());
1179
+ if (op == Binary_Expression::MOD) error("invalid operands for modulo", lhs->pstate());
1085
1180
  string sep;
1086
1181
  switch (op) {
1087
1182
  case Binary_Expression::SUB: sep = "-"; break;
1088
1183
  case Binary_Expression::DIV: sep = "/"; break;
1089
1184
  default: break;
1090
1185
  }
1091
- if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs->path(), lhs->position());
1092
- if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", lhs->path(), lhs->position());
1093
- char q = '\0';
1094
- if (lstr[0] == '"' || lstr[0] == '\'') q = lstr[0];
1095
- else if (rstr[0] == '"' || rstr[0] == '\'') q = rstr[0];
1096
- string result(unquote(lstr) + sep + unquote(rstr));
1097
- return new (ctx.mem) String_Constant(lhs->path(),
1098
- lhs->position(),
1099
- unquoted ? result : quote(result, q));
1186
+ if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs->pstate());
1187
+ if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", lhs->pstate());
1188
+ string result((lstr) + sep + (rstr));
1189
+ String_Quoted* str = new (ctx.mem) String_Quoted(lhs->pstate(), result);
1190
+ str->quote_mark(0);
1191
+ return str;
1100
1192
  }
1101
1193
 
1102
- Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, string path, Position position)
1194
+ Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
1103
1195
  {
1104
1196
  using std::strlen;
1105
1197
  using std::strcpy;
1106
1198
  Expression* e = 0;
1107
1199
  switch (sass_value_get_tag(v)) {
1108
1200
  case SASS_BOOLEAN: {
1109
- e = new (ctx.mem) Boolean(path, position, !!sass_boolean_get_value(v));
1201
+ e = new (ctx.mem) Boolean(pstate, !!sass_boolean_get_value(v));
1110
1202
  } break;
1111
1203
  case SASS_NUMBER: {
1112
- e = new (ctx.mem) Number(path, position, sass_number_get_value(v), sass_number_get_unit(v));
1204
+ e = new (ctx.mem) Number(pstate, sass_number_get_value(v), sass_number_get_unit(v));
1113
1205
  } break;
1114
1206
  case SASS_COLOR: {
1115
- e = new (ctx.mem) Color(path, position, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
1207
+ e = new (ctx.mem) Color(pstate, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
1116
1208
  } break;
1117
1209
  case SASS_STRING: {
1118
- e = new (ctx.mem) String_Constant(path, position, sass_string_get_value(v));
1210
+ e = new (ctx.mem) String_Constant(pstate, sass_string_get_value(v));
1119
1211
  } break;
1120
1212
  case SASS_LIST: {
1121
- List* l = new (ctx.mem) List(path, position, sass_list_get_length(v), sass_list_get_separator(v) == SASS_COMMA ? List::COMMA : List::SPACE);
1213
+ List* l = new (ctx.mem) List(pstate, sass_list_get_length(v), sass_list_get_separator(v) == SASS_COMMA ? List::COMMA : List::SPACE);
1122
1214
  for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) {
1123
- *l << cval_to_astnode(sass_list_get_value(v, i), ctx, backtrace, path, position);
1215
+ *l << cval_to_astnode(sass_list_get_value(v, i), ctx, backtrace, pstate);
1124
1216
  }
1125
1217
  e = l;
1126
1218
  } break;
1127
1219
  case SASS_MAP: {
1128
- Map* m = new (ctx.mem) Map(path, position);
1220
+ Map* m = new (ctx.mem) Map(pstate);
1129
1221
  for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) {
1130
1222
  *m << std::make_pair(
1131
- cval_to_astnode(sass_map_get_key(v, i), ctx, backtrace, path, position),
1132
- cval_to_astnode(sass_map_get_value(v, i), ctx, backtrace, path, position));
1223
+ cval_to_astnode(sass_map_get_key(v, i), ctx, backtrace, pstate),
1224
+ cval_to_astnode(sass_map_get_value(v, i), ctx, backtrace, pstate));
1133
1225
  }
1134
1226
  e = m;
1135
1227
  } break;
1136
1228
  case SASS_NULL: {
1137
- e = new (ctx.mem) Null(path, position);
1229
+ e = new (ctx.mem) Null(pstate);
1138
1230
  } break;
1139
1231
  case SASS_ERROR: {
1140
- error("Error in C function: " + string(sass_error_get_message(v)), path, position, backtrace);
1232
+ error("Error in C function: " + string(sass_error_get_message(v)), pstate, backtrace);
1141
1233
  } break;
1142
1234
  case SASS_WARNING: {
1143
- error("Warning in C function: " + string(sass_warning_get_message(v)), path, position, backtrace);
1235
+ error("Warning in C function: " + string(sass_warning_get_message(v)), pstate, backtrace);
1144
1236
  } break;
1145
1237
  }
1146
1238
  return e;