sassc 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
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);