sassc 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/libsass/.gitignore +6 -0
  4. data/ext/libsass/.travis.yml +5 -1
  5. data/ext/libsass/Makefile +12 -3
  6. data/ext/libsass/Makefile.am +16 -28
  7. data/ext/libsass/Readme.md +1 -0
  8. data/ext/libsass/appveyor.yml +1 -2
  9. data/ext/libsass/ast.cpp +9 -0
  10. data/ext/libsass/ast.hpp +152 -55
  11. data/ext/libsass/ast_factory.hpp +2 -0
  12. data/ext/libsass/ast_fwd_decl.hpp +1 -0
  13. data/ext/libsass/backtrace.hpp +2 -2
  14. data/ext/libsass/bind.cpp +15 -13
  15. data/ext/libsass/configure.ac +17 -5
  16. data/ext/libsass/constants.cpp +22 -2
  17. data/ext/libsass/constants.hpp +21 -2
  18. data/ext/libsass/context.cpp +79 -57
  19. data/ext/libsass/context.hpp +23 -9
  20. data/ext/libsass/contextualize.cpp +2 -28
  21. data/ext/libsass/contextualize.hpp +6 -10
  22. data/ext/libsass/contextualize_eval.cpp +93 -0
  23. data/ext/libsass/contextualize_eval.hpp +44 -0
  24. data/ext/libsass/contrib/plugin.cpp +57 -0
  25. data/ext/libsass/cssize.cpp +3 -1
  26. data/ext/libsass/debugger.hpp +242 -83
  27. data/ext/libsass/emitter.cpp +1 -1
  28. data/ext/libsass/emitter.hpp +1 -1
  29. data/ext/libsass/environment.hpp +109 -25
  30. data/ext/libsass/error_handling.cpp +3 -3
  31. data/ext/libsass/error_handling.hpp +0 -1
  32. data/ext/libsass/eval.cpp +145 -61
  33. data/ext/libsass/eval.hpp +9 -1
  34. data/ext/libsass/expand.cpp +134 -60
  35. data/ext/libsass/expand.hpp +5 -2
  36. data/ext/libsass/extend.cpp +7 -5
  37. data/ext/libsass/file.cpp +176 -123
  38. data/ext/libsass/file.hpp +44 -7
  39. data/ext/libsass/functions.cpp +36 -17
  40. data/ext/libsass/functions.hpp +2 -2
  41. data/ext/libsass/inspect.cpp +23 -14
  42. data/ext/libsass/inspect.hpp +1 -0
  43. data/ext/libsass/json.cpp +132 -135
  44. data/ext/libsass/lexer.cpp +133 -0
  45. data/ext/libsass/lexer.hpp +239 -0
  46. data/ext/libsass/listize.cpp +83 -0
  47. data/ext/libsass/listize.hpp +41 -0
  48. data/ext/libsass/operation.hpp +2 -0
  49. data/ext/libsass/output.cpp +5 -6
  50. data/ext/libsass/parser.cpp +426 -388
  51. data/ext/libsass/parser.hpp +97 -109
  52. data/ext/libsass/plugins.cpp +15 -2
  53. data/ext/libsass/plugins.hpp +6 -4
  54. data/ext/libsass/position.cpp +52 -17
  55. data/ext/libsass/position.hpp +19 -17
  56. data/ext/libsass/prelexer.cpp +202 -235
  57. data/ext/libsass/prelexer.hpp +73 -333
  58. data/ext/libsass/sass.cpp +21 -11
  59. data/ext/libsass/sass.h +6 -6
  60. data/ext/libsass/sass_context.cpp +167 -81
  61. data/ext/libsass/sass_context.h +26 -6
  62. data/ext/libsass/sass_functions.cpp +49 -40
  63. data/ext/libsass/sass_functions.h +55 -43
  64. data/ext/libsass/sass_interface.cpp +9 -8
  65. data/ext/libsass/sass_interface.h +3 -3
  66. data/ext/libsass/sass_version.h +8 -0
  67. data/ext/libsass/sass_version.h.in +8 -0
  68. data/ext/libsass/script/ci-build-libsass +3 -3
  69. data/ext/libsass/script/ci-report-coverage +2 -1
  70. data/ext/libsass/source_map.cpp +2 -2
  71. data/ext/libsass/util.cpp +60 -11
  72. data/ext/libsass/util.hpp +6 -1
  73. data/ext/libsass/win/libsass.filters +12 -0
  74. data/ext/libsass/win/libsass.vcxproj +10 -0
  75. data/lib/sassc.rb +3 -1
  76. data/lib/sassc/cache_stores/base.rb +2 -0
  77. data/lib/sassc/dependency.rb +3 -1
  78. data/lib/sassc/engine.rb +31 -16
  79. data/lib/sassc/error.rb +3 -2
  80. data/lib/sassc/functions_handler.rb +54 -0
  81. data/lib/sassc/import_handler.rb +41 -0
  82. data/lib/sassc/importer.rb +4 -31
  83. data/lib/sassc/native.rb +1 -1
  84. data/lib/sassc/native/native_context_api.rb +3 -2
  85. data/lib/sassc/script.rb +0 -51
  86. data/lib/sassc/version.rb +1 -1
  87. data/sassc.gemspec +1 -0
  88. data/test/custom_importer_test.rb +72 -69
  89. data/test/engine_test.rb +53 -54
  90. data/test/functions_test.rb +40 -39
  91. data/test/native_test.rb +145 -149
  92. data/test/output_style_test.rb +98 -0
  93. data/test/test_helper.rb +21 -7
  94. metadata +28 -2
@@ -15,7 +15,7 @@ namespace Sass {
15
15
  scheduled_linefeed(0),
16
16
  scheduled_delimiter(false),
17
17
  in_comment(false),
18
- in_at_rule(false),
18
+ in_wrapped(false),
19
19
  in_media_block(false),
20
20
  in_declaration(false),
21
21
  in_declaration_list(false)
@@ -38,7 +38,7 @@ namespace Sass {
38
38
 
39
39
  public:
40
40
  bool in_comment;
41
- bool in_at_rule;
41
+ bool in_wrapped;
42
42
  bool in_media_block;
43
43
  bool in_declaration;
44
44
  bool in_declaration_list;
@@ -5,7 +5,9 @@
5
5
  #include <string>
6
6
  #include <iostream>
7
7
 
8
+ #include "ast_fwd_decl.hpp"
8
9
  #include "ast_def_macros.hpp"
10
+ #include "memory_manager.hpp"
9
11
 
10
12
  namespace Sass {
11
13
  using std::string;
@@ -16,56 +18,136 @@ namespace Sass {
16
18
  template <typename T>
17
19
  class Environment {
18
20
  // TODO: test with unordered_map
19
- map<string, T> current_frame_;
21
+ map<string, T> local_frame_;
20
22
  ADD_PROPERTY(Environment*, parent);
21
23
 
22
24
  public:
23
- Environment() : current_frame_(map<string, T>()), parent_(0) { }
24
-
25
- map<string, T>& current_frame() { return current_frame_; }
25
+ Memory_Manager<AST_Node> mem;
26
+ Environment() : local_frame_(map<string, T>()), parent_(0) { }
26
27
 
28
+ // link parent to create a stack
27
29
  void link(Environment& env) { parent_ = &env; }
28
30
  void link(Environment* env) { parent_ = env; }
29
31
 
30
- bool has(const string key) const
32
+ // this is used to find the global frame
33
+ // which is the second last on the stack
34
+ bool is_lexical() const
35
+ {
36
+ return !! parent_ && parent_->parent_;
37
+ }
38
+
39
+ // only match the real root scope
40
+ // there is still a parent around
41
+ // not sure what it is actually use for
42
+ // I guess we store functions etc. there
43
+ bool is_root_scope() const
31
44
  {
32
- if (current_frame_.count(key)) return true;
33
- else if (parent_) return parent_->has(key);
34
- else return false;
45
+ return parent_ && ! parent_->parent_;
46
+ }
47
+
48
+ // scope operates on the current frame
49
+
50
+ map<string, T>& local_frame() {
51
+ return local_frame_;
35
52
  }
36
53
 
37
- bool current_frame_has(const string key) const
38
- { return !!current_frame_.count(key); }
54
+ bool has_local(const string& key) const
55
+ { return local_frame_.count(key); }
39
56
 
40
- Environment* grandparent() const
57
+ T& get_local(const string& key)
58
+ { return local_frame_[key]; }
59
+
60
+ void set_local(const string& key, T val)
61
+ { local_frame_[key] = val; }
62
+
63
+ void del_local(const string& key)
64
+ { local_frame_.erase(key); }
65
+
66
+
67
+ // global operates on the global frame
68
+ // which is the second last on the stack
69
+
70
+ Environment* global_env()
41
71
  {
42
- if(parent_ && parent_->parent_) return parent_->parent_;
43
- else return 0;
72
+ Environment* cur = this;
73
+ while (cur->is_lexical()) {
74
+ cur = cur->parent_;
75
+ }
76
+ return cur;
44
77
  }
45
78
 
46
- bool global_frame_has(const string key) const
79
+ bool has_global(const string& key)
80
+ { return global_env()->has(key); }
81
+
82
+ T& get_global(const string& key)
83
+ { return (*global_env())[key]; }
84
+
85
+ void set_global(const string& key, T val)
86
+ { global_env()->local_frame_[key] = val; }
87
+
88
+ void del_global(const string& key)
89
+ { global_env()->local_frame_.erase(key); }
90
+
91
+ // see if we have a lexical variable
92
+ // move down the stack but stop before we
93
+ // reach the global frame (is not included)
94
+ bool has_lexical(const string& key) const
47
95
  {
48
- if(parent_ && !grandparent()) {
49
- return has(key);
96
+ auto cur = this;
97
+ while (cur->is_lexical()) {
98
+ if (cur->has_local(key)) return true;
99
+ cur = cur->parent_;
50
100
  }
51
- else if(parent_) {
52
- return parent_->global_frame_has(key);
101
+ return false;
102
+ }
103
+
104
+ // see if we have a lexical we could update
105
+ // either update already existing lexical value
106
+ // or if flag is set, we create one if no lexical found
107
+ void set_lexical(const string& key, T val)
108
+ {
109
+ auto cur = this;
110
+ while (cur->is_lexical()) {
111
+ if (cur->has_local(key)) {
112
+ cur->set_local(key, val);
113
+ return;
114
+ }
115
+ cur = cur->parent_;
53
116
  }
54
- else {
55
- return false;
117
+ set_local(key, val);
118
+ }
119
+
120
+ // look on the full stack for key
121
+ // include all scopes available
122
+ bool has(const string& key) const
123
+ {
124
+ auto cur = this;
125
+ while (cur) {
126
+ if (cur->has_local(key)) {
127
+ return true;
128
+ }
129
+ cur = cur->parent_;
56
130
  }
131
+ return false;
57
132
  }
58
133
 
59
- T& operator[](const string key)
134
+ // use array access for getter and setter functions
135
+ T& operator[](const string& key)
60
136
  {
61
- if (current_frame_.count(key)) return current_frame_[key];
62
- else if (parent_) return (*parent_)[key];
63
- else return current_frame_[key];
137
+ auto cur = this;
138
+ while (cur) {
139
+ if (cur->has_local(key)) {
140
+ return cur->get_local(key);
141
+ }
142
+ cur = cur->parent_;
143
+ }
144
+ return get_local(key);
64
145
  }
65
146
 
147
+ #ifdef DEBUG
66
148
  void print()
67
149
  {
68
- for (typename map<string, T>::iterator i = current_frame_.begin(); i != current_frame_.end(); ++i) {
150
+ for (typename map<string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
69
151
  cerr << i->first << endl;
70
152
  }
71
153
  if (parent_) {
@@ -73,6 +155,8 @@ namespace Sass {
73
155
  parent_->print();
74
156
  }
75
157
  }
158
+ #endif
159
+
76
160
  };
77
161
  }
78
162
 
@@ -9,12 +9,12 @@ namespace Sass {
9
9
  { }
10
10
 
11
11
  void error(string msg, ParserState pstate)
12
- { throw Sass_Error(Sass_Error::syntax, pstate, msg); }
12
+ {
13
+ throw Sass_Error(Sass_Error::syntax, pstate, msg);
14
+ }
13
15
 
14
16
  void error(string msg, ParserState pstate, Backtrace* bt)
15
17
  {
16
- if (!pstate.path.empty() && Prelexer::quoted_string(pstate.path.c_str()))
17
- pstate.path = pstate.path.substr(1, pstate.path.size() - 1);
18
18
 
19
19
  Backtrace top(bt, pstate, "");
20
20
  msg += top.to_string();
@@ -14,7 +14,6 @@ namespace Sass {
14
14
  enum Type { read, write, syntax, evaluation };
15
15
 
16
16
  Type type;
17
- string path;
18
17
  ParserState pstate;
19
18
  string message;
20
19
 
@@ -31,12 +31,21 @@ namespace Sass {
31
31
  add, sub, mul, div, fmod
32
32
  };
33
33
 
34
- Eval::Eval(Context& ctx, Env* env, Backtrace* bt)
35
- : ctx(ctx), env(env), backtrace(bt) { }
34
+ Eval::Eval(Context& ctx, Contextualize* contextualize, Listize* listize, Env* env, Backtrace* bt)
35
+ : ctx(ctx), contextualize(contextualize), listize(listize), env(env), backtrace(bt) { }
36
36
  Eval::~Eval() { }
37
37
 
38
38
  Eval* Eval::with(Env* e, Backtrace* bt) // for setting the env before eval'ing an expression
39
39
  {
40
+ contextualize = contextualize->with(0, e, bt);
41
+ env = e;
42
+ backtrace = bt;
43
+ return this;
44
+ }
45
+
46
+ Eval* Eval::with(Selector* c, Env* e, Backtrace* bt, Selector* p, Selector* ex) // for setting the env before eval'ing an expression
47
+ {
48
+ contextualize = contextualize->with(c, e, bt, p, ex);
40
49
  env = e;
41
50
  backtrace = bt;
42
51
  return this;
@@ -55,12 +64,59 @@ namespace Sass {
55
64
  Expression* Eval::operator()(Assignment* a)
56
65
  {
57
66
  string var(a->variable());
58
- if (env->has(var)) {
59
- Expression* v = static_cast<Expression*>((*env)[var]);
60
- if (!a->is_guarded() || v->concrete_type() == Expression::NULL_VAL) (*env)[var] = a->value()->perform(this);
67
+ if (a->is_global()) {
68
+ if (a->is_default()) {
69
+ if (env->has_global(var)) {
70
+ Expression* e = dynamic_cast<Expression*>(env->get_global(var));
71
+ if (!e || e->concrete_type() == Expression::NULL_VAL) {
72
+ env->set_global(var, a->value()->perform(this));
73
+ }
74
+ }
75
+ else {
76
+ env->set_global(var, a->value()->perform(this));
77
+ }
78
+ }
79
+ else {
80
+ env->set_global(var, a->value()->perform(this));
81
+ }
82
+ }
83
+ else if (a->is_default()) {
84
+ if (env->has_lexical(var)) {
85
+ auto cur = env;
86
+ while (cur && cur->is_lexical()) {
87
+ if (cur->has_local(var)) {
88
+ if (AST_Node* node = cur->get_local(var)) {
89
+ Expression* e = dynamic_cast<Expression*>(node);
90
+ if (!e || e->concrete_type() == Expression::NULL_VAL) {
91
+ cur->set_local(var, a->value()->perform(this));
92
+ }
93
+ }
94
+ else {
95
+ throw runtime_error("Env not in sync");
96
+ }
97
+ return 0;
98
+ }
99
+ cur = cur->parent();
100
+ }
101
+ throw runtime_error("Env not in sync");
102
+ }
103
+ else if (env->has_global(var)) {
104
+ if (AST_Node* node = env->get_global(var)) {
105
+ Expression* e = dynamic_cast<Expression*>(node);
106
+ if (!e || e->concrete_type() == Expression::NULL_VAL) {
107
+ env->set_global(var, a->value()->perform(this));
108
+ }
109
+ }
110
+ }
111
+ else if (env->is_lexical()) {
112
+ env->set_local(var, a->value()->perform(this));
113
+ }
114
+ else {
115
+ env->set_local(var, a->value()->perform(this));
116
+ }
61
117
  }
62
118
  else {
63
- env->current_frame()[var] = a->value()->perform(this);
119
+ env->set_lexical(var, a->value()->perform(this));
64
120
  }
65
121
  return 0;
66
122
  }
@@ -77,6 +133,8 @@ namespace Sass {
77
133
  return 0;
78
134
  }
79
135
 
136
+ // For does not create a new env scope
137
+ // But iteration vars are reset afterwards
80
138
  Expression* Eval::operator()(For* f)
81
139
  {
82
140
  string variable(f->variable());
@@ -88,19 +146,30 @@ namespace Sass {
88
146
  if (high->concrete_type() != Expression::NUMBER) {
89
147
  error("upper bound of `@for` directive must be numeric", high->pstate());
90
148
  }
91
- double start = static_cast<Number*>(low)->value();
92
- double end = static_cast<Number*>(high)->value();
93
- Env new_env;
94
- new_env[variable] = new (ctx.mem) Number(low->pstate(), start);
95
- new_env.link(env);
96
- env = &new_env;
149
+ Number* sass_start = static_cast<Number*>(low);
150
+ Number* sass_end = static_cast<Number*>(high);
151
+ // check if units are valid for sequence
152
+ if (sass_start->unit() != sass_end->unit()) {
153
+ stringstream msg; msg << "Incompatible units: '"
154
+ << sass_start->unit() << "' and '"
155
+ << sass_end->unit() << "'.";
156
+ error(msg.str(), low->pstate(), backtrace);
157
+ }
158
+ double start = sass_start->value();
159
+ double end = sass_end->value();
160
+ // only create iterator once in this environment
161
+ Number* it = new (env->mem) Number(low->pstate(), start, sass_end->unit());
162
+ AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0;
163
+ env->set_local(variable, it);
97
164
  Block* body = f->block();
98
165
  Expression* val = 0;
99
166
  if (start < end) {
100
167
  if (f->is_inclusive()) ++end;
101
168
  for (double i = start;
102
169
  i < end;
103
- (*env)[variable] = new (ctx.mem) Number(low->pstate(), ++i)) {
170
+ ++i) {
171
+ it->value(i);
172
+ env->set_local(variable, it);
104
173
  val = body->perform(this);
105
174
  if (val) break;
106
175
  }
@@ -108,15 +177,21 @@ namespace Sass {
108
177
  if (f->is_inclusive()) --end;
109
178
  for (double i = start;
110
179
  i > end;
111
- (*env)[variable] = new (ctx.mem) Number(low->pstate(), --i)) {
180
+ --i) {
181
+ it->value(i);
182
+ env->set_local(variable, it);
112
183
  val = body->perform(this);
113
184
  if (val) break;
114
185
  }
115
186
  }
116
- env = new_env.parent();
187
+ // restore original environment
188
+ if (!old_var) env->del_local(variable);
189
+ else env->set_local(variable, old_var);
117
190
  return val;
118
191
  }
119
192
 
193
+ // Eval does not create a new env scope
194
+ // But iteration vars are reset afterwards
120
195
  Expression* Eval::operator()(Each* e)
121
196
  {
122
197
  vector<string> variables(e->variables());
@@ -133,10 +208,12 @@ namespace Sass {
133
208
  else {
134
209
  list = static_cast<List*>(expr);
135
210
  }
136
- Env new_env;
137
- for (size_t i = 0, L = variables.size(); i < L; ++i) new_env[variables[i]] = 0;
138
- new_env.link(env);
139
- env = &new_env;
211
+ // remember variables and then reset them
212
+ vector<AST_Node*> old_vars(variables.size());
213
+ for (size_t i = 0, L = variables.size(); i < L; ++i) {
214
+ old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
215
+ env->set_local(variables[i], 0);
216
+ }
140
217
  Block* body = e->block();
141
218
  Expression* val = 0;
142
219
 
@@ -148,10 +225,10 @@ namespace Sass {
148
225
  List* variable = new (ctx.mem) List(map->pstate(), 2, List::SPACE);
149
226
  *variable << key;
150
227
  *variable << value;
151
- (*env)[variables[0]] = variable;
228
+ env->set_local(variables[0], variable);
152
229
  } else {
153
- (*env)[variables[0]] = key;
154
- (*env)[variables[1]] = value;
230
+ env->set_local(variables[0], key);
231
+ env->set_local(variables[1], value);
155
232
  }
156
233
 
157
234
  val = body->perform(this);
@@ -170,10 +247,10 @@ namespace Sass {
170
247
  }
171
248
  for (size_t j = 0, K = variables.size(); j < K; ++j) {
172
249
  if (j < variable->length()) {
173
- (*env)[variables[j]] = (*variable)[j];
250
+ env->set_local(variables[j], (*variable)[j]);
174
251
  }
175
252
  else {
176
- (*env)[variables[j]] = new (ctx.mem) Null(expr->pstate());
253
+ env->set_local(variables[j], new (ctx.mem) Null(expr->pstate()));
177
254
  }
178
255
  val = body->perform(this);
179
256
  if (val) break;
@@ -181,7 +258,11 @@ namespace Sass {
181
258
  if (val) break;
182
259
  }
183
260
  }
184
- env = new_env.parent();
261
+ // restore original environment
262
+ for (size_t j = 0, K = variables.size(); j < K; ++j) {
263
+ if(!old_vars[j]) env->del_local(variables[j]);
264
+ else env->set_local(variables[j], old_vars[j]);
265
+ }
185
266
  return val;
186
267
  }
187
268
 
@@ -212,12 +293,13 @@ namespace Sass {
212
293
  Definition* def = static_cast<Definition*>((*env)["@warn[f]"]);
213
294
  // Block* body = def->block();
214
295
  // Native_Function func = def->native_function();
215
- Sass_C_Function c_func = def->c_function();
296
+ Sass_Function_Entry c_function = def->c_function();
297
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
216
298
 
217
299
  To_C to_c;
218
300
  union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
219
301
  sass_list_set_value(c_args, 0, message->perform(&to_c));
220
- Sass_Value* c_val = c_func(c_args, def->cookie());
302
+ Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
221
303
  sass_delete_value(c_args);
222
304
  sass_delete_value(c_val);
223
305
  return 0;
@@ -243,12 +325,13 @@ namespace Sass {
243
325
  Definition* def = static_cast<Definition*>((*env)["@error[f]"]);
244
326
  // Block* body = def->block();
245
327
  // Native_Function func = def->native_function();
246
- Sass_C_Function c_func = def->c_function();
328
+ Sass_Function_Entry c_function = def->c_function();
329
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
247
330
 
248
331
  To_C to_c;
249
332
  union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
250
333
  sass_list_set_value(c_args, 0, message->perform(&to_c));
251
- Sass_Value* c_val = c_func(c_args, def->cookie());
334
+ Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
252
335
  sass_delete_value(c_args);
253
336
  sass_delete_value(c_val);
254
337
  return 0;
@@ -256,10 +339,7 @@ namespace Sass {
256
339
  }
257
340
 
258
341
  string result(unquote(message->perform(&to_string)));
259
- Backtrace top(backtrace, e->pstate(), "");
260
- cerr << "Error: " << result;
261
- cerr << top.to_string(true);
262
- cerr << endl << endl;
342
+ error(result, e->pstate());
263
343
  return 0;
264
344
  }
265
345
 
@@ -274,12 +354,13 @@ namespace Sass {
274
354
  Definition* def = static_cast<Definition*>((*env)["@debug[f]"]);
275
355
  // Block* body = def->block();
276
356
  // Native_Function func = def->native_function();
277
- Sass_C_Function c_func = def->c_function();
357
+ Sass_Function_Entry c_function = def->c_function();
358
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
278
359
 
279
360
  To_C to_c;
280
361
  union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
281
362
  sass_list_set_value(c_args, 0, message->perform(&to_c));
282
- Sass_Value* c_val = c_func(c_args, def->cookie());
363
+ Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
283
364
  sass_delete_value(c_args);
284
365
  sass_delete_value(c_val);
285
366
  return 0;
@@ -431,7 +512,8 @@ namespace Sass {
431
512
 
432
513
  Expression* Eval::operator()(Function_Call* c)
433
514
  {
434
- string full_name(c->name() + "[f]");
515
+ string name(Util::normalize_underscores(c->name()));
516
+ string full_name(name + "[f]");
435
517
  Arguments* args = c->arguments();
436
518
  if (full_name != "if[f]") {
437
519
  args = static_cast<Arguments*>(args->perform(this));
@@ -458,7 +540,7 @@ namespace Sass {
458
540
  Definition* def = static_cast<Definition*>((*env)[full_name]);
459
541
  Block* body = def->block();
460
542
  Native_Function func = def->native_function();
461
- Sass_C_Function c_func = def->c_function();
543
+ Sass_Function_Entry c_function = def->c_function();
462
544
 
463
545
  if (full_name != "if[f]") {
464
546
  for (size_t i = 0, L = args->length(); i < L; ++i) {
@@ -509,8 +591,9 @@ namespace Sass {
509
591
  env = old_env;
510
592
  }
511
593
  // else if it's a user-defined c function
512
- else if (c_func) {
594
+ else if (c_function) {
513
595
 
596
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
514
597
  if (full_name == "*[f]") {
515
598
  String_Constant *str = new (ctx.mem) String_Constant(c->pstate(), c->name());
516
599
  Arguments* new_args = new (ctx.mem) Arguments(c->pstate());
@@ -528,14 +611,14 @@ namespace Sass {
528
611
  backtrace = &here;
529
612
 
530
613
  To_C to_c;
531
- union Sass_Value* c_args = sass_make_list(env->current_frame().size(), SASS_COMMA);
614
+ union Sass_Value* c_args = sass_make_list(env->local_frame().size(), SASS_COMMA);
532
615
  for(size_t i = 0; i < params[0].length(); i++) {
533
616
  string key = params[0][i]->name();
534
- AST_Node* node = env->current_frame().at(key);
617
+ AST_Node* node = env->local_frame().at(key);
535
618
  Expression* arg = static_cast<Expression*>(node);
536
619
  sass_list_set_value(c_args, i, arg->perform(&to_c));
537
620
  }
538
- Sass_Value* c_val = c_func(c_args, def->cookie());
621
+ Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
539
622
  if (sass_value_get_tag(c_val) == SASS_ERROR) {
540
623
  error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), backtrace);
541
624
  } else if (sass_value_get_tag(c_val) == SASS_WARNING) {
@@ -671,7 +754,7 @@ namespace Sass {
671
754
  case Textual::DIMENSION:
672
755
  result = new (ctx.mem) Number(t->pstate(),
673
756
  sass_atof(num.c_str()),
674
- Token(number(text.c_str()), t->pstate()),
757
+ Token(number(text.c_str())),
675
758
  zero);
676
759
  break;
677
760
  case Textual::HEX: {
@@ -727,21 +810,15 @@ namespace Sass {
727
810
  }
728
811
 
729
812
  string Eval::interpolation(Expression* s) {
730
-
731
813
  if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
732
-
733
814
  if (str_quoted->quote_mark()) {
734
815
  return string_escape(str_quoted->value());
735
816
  } else {
736
817
  return evacuate_escapes(str_quoted->value());
737
818
  }
738
-
739
819
  } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
740
-
741
820
  return evacuate_escapes(str_constant->value());
742
-
743
821
  } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
744
-
745
822
  string res = "";
746
823
  for(auto i : str_schema->elements())
747
824
  res += (interpolation(i));
@@ -753,9 +830,7 @@ namespace Sass {
753
830
  } else {
754
831
  return evacuate_quotes(unq);
755
832
  }
756
-
757
833
  } else if (List* list = dynamic_cast<List*>(s)) {
758
-
759
834
  string acc = ""; // ToDo: different output styles
760
835
  string sep = list->separator() == List::Separator::COMMA ? "," : " ";
761
836
  if (ctx.output_style != COMPRESSED && sep == ",") sep += " ";
@@ -766,30 +841,30 @@ namespace Sass {
766
841
  initial = true;
767
842
  }
768
843
  return evacuate_quotes(acc);
769
-
770
844
  } else if (Variable* var = dynamic_cast<Variable*>(s)) {
771
-
772
845
  string name(var->name());
773
846
  if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate());
774
847
  Expression* value = static_cast<Expression*>((*env)[name]);
775
848
  return evacuate_quotes(interpolation(value));
776
-
777
849
  } else if (Binary_Expression* var = dynamic_cast<Binary_Expression*>(s)) {
778
-
779
- Expression* ex = operator()(var);
850
+ Expression* ex = var->perform(this);
780
851
  return evacuate_quotes(interpolation(ex));
781
-
782
852
  } else if (Function_Call* var = dynamic_cast<Function_Call*>(s)) {
783
-
784
- Expression* ex = operator()(var);
853
+ Expression* ex = var->perform(this);
854
+ return evacuate_quotes(interpolation(ex));
855
+ } else if (Parent_Selector* var = dynamic_cast<Parent_Selector*>(s)) {
856
+ Expression* ex = var->perform(this);
857
+ return evacuate_quotes(interpolation(ex));
858
+ } else if (Unary_Expression* var = dynamic_cast<Unary_Expression*>(s)) {
859
+ Expression* ex = var->perform(this);
860
+ return evacuate_quotes(interpolation(ex));
861
+ } else if (Selector* var = dynamic_cast<Selector*>(s)) {
862
+ Expression* ex = var->perform(this);
785
863
  return evacuate_quotes(interpolation(ex));
786
-
787
864
  } else {
788
-
789
865
  To_String to_string(&ctx);
790
866
  // to_string.in_decl_list = true;
791
867
  return evacuate_quotes(s->perform(&to_string));
792
-
793
868
  }
794
869
  }
795
870
 
@@ -938,6 +1013,15 @@ namespace Sass {
938
1013
  return 0;
939
1014
  }
940
1015
 
1016
+ Expression* Eval::operator()(Parent_Selector* p)
1017
+ {
1018
+ Selector* s = p->perform(contextualize);
1019
+ // access to parent selector may return 0
1020
+ Selector_List* l = static_cast<Selector_List*>(s);
1021
+ if (!s) { l = new (ctx.mem) Selector_List(p->pstate()); }
1022
+ return l->perform(listize);
1023
+ }
1024
+
941
1025
  inline Expression* Eval::fallback_impl(AST_Node* n)
942
1026
  {
943
1027
  return static_cast<Expression*>(n);