sassc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +24 -0
  8. data/Rakefile +21 -0
  9. data/ext/libsass/.editorconfig +15 -0
  10. data/ext/libsass/.gitattributes +2 -0
  11. data/ext/libsass/.gitignore +61 -0
  12. data/ext/libsass/.travis.yml +38 -0
  13. data/ext/libsass/COPYING +25 -0
  14. data/ext/libsass/INSTALL +1 -0
  15. data/ext/libsass/LICENSE +25 -0
  16. data/ext/libsass/Makefile +223 -0
  17. data/ext/libsass/Makefile.am +145 -0
  18. data/ext/libsass/Readme.md +93 -0
  19. data/ext/libsass/appveyor.yml +76 -0
  20. data/ext/libsass/ast.cpp +581 -0
  21. data/ext/libsass/ast.hpp +1949 -0
  22. data/ext/libsass/ast_def_macros.hpp +16 -0
  23. data/ext/libsass/ast_factory.hpp +87 -0
  24. data/ext/libsass/ast_fwd_decl.hpp +72 -0
  25. data/ext/libsass/b64/cencode.h +32 -0
  26. data/ext/libsass/b64/encode.h +77 -0
  27. data/ext/libsass/backtrace.hpp +81 -0
  28. data/ext/libsass/base64vlq.cpp +43 -0
  29. data/ext/libsass/base64vlq.hpp +28 -0
  30. data/ext/libsass/bind.cpp +187 -0
  31. data/ext/libsass/bind.hpp +18 -0
  32. data/ext/libsass/cencode.c +102 -0
  33. data/ext/libsass/color_names.hpp +324 -0
  34. data/ext/libsass/configure.ac +130 -0
  35. data/ext/libsass/constants.cpp +144 -0
  36. data/ext/libsass/constants.hpp +145 -0
  37. data/ext/libsass/context.cpp +507 -0
  38. data/ext/libsass/context.hpp +150 -0
  39. data/ext/libsass/contextualize.cpp +157 -0
  40. data/ext/libsass/contextualize.hpp +65 -0
  41. data/ext/libsass/copy_c_str.cpp +13 -0
  42. data/ext/libsass/copy_c_str.hpp +5 -0
  43. data/ext/libsass/debug.hpp +39 -0
  44. data/ext/libsass/environment.hpp +75 -0
  45. data/ext/libsass/error_handling.cpp +28 -0
  46. data/ext/libsass/error_handling.hpp +28 -0
  47. data/ext/libsass/eval.cpp +1149 -0
  48. data/ext/libsass/eval.hpp +80 -0
  49. data/ext/libsass/expand.cpp +430 -0
  50. data/ext/libsass/expand.hpp +77 -0
  51. data/ext/libsass/extconf.rb +6 -0
  52. data/ext/libsass/extend.cpp +1962 -0
  53. data/ext/libsass/extend.hpp +50 -0
  54. data/ext/libsass/file.cpp +291 -0
  55. data/ext/libsass/file.hpp +18 -0
  56. data/ext/libsass/functions.cpp +1565 -0
  57. data/ext/libsass/functions.hpp +187 -0
  58. data/ext/libsass/inspect.cpp +727 -0
  59. data/ext/libsass/inspect.hpp +108 -0
  60. data/ext/libsass/json.cpp +1411 -0
  61. data/ext/libsass/json.hpp +117 -0
  62. data/ext/libsass/kwd_arg_macros.hpp +23 -0
  63. data/ext/libsass/m4/.gitkeep +0 -0
  64. data/ext/libsass/mapping.hpp +17 -0
  65. data/ext/libsass/memory_manager.hpp +54 -0
  66. data/ext/libsass/node.cpp +251 -0
  67. data/ext/libsass/node.hpp +122 -0
  68. data/ext/libsass/operation.hpp +153 -0
  69. data/ext/libsass/output_compressed.cpp +401 -0
  70. data/ext/libsass/output_compressed.hpp +95 -0
  71. data/ext/libsass/output_nested.cpp +364 -0
  72. data/ext/libsass/output_nested.hpp +108 -0
  73. data/ext/libsass/parser.cpp +2016 -0
  74. data/ext/libsass/parser.hpp +264 -0
  75. data/ext/libsass/paths.hpp +69 -0
  76. data/ext/libsass/position.hpp +22 -0
  77. data/ext/libsass/posix/getopt.c +562 -0
  78. data/ext/libsass/posix/getopt.h +95 -0
  79. data/ext/libsass/prelexer.cpp +688 -0
  80. data/ext/libsass/prelexer.hpp +513 -0
  81. data/ext/libsass/remove_placeholders.cpp +59 -0
  82. data/ext/libsass/remove_placeholders.hpp +43 -0
  83. data/ext/libsass/res/resource.rc +35 -0
  84. data/ext/libsass/sass.cpp +33 -0
  85. data/ext/libsass/sass.h +60 -0
  86. data/ext/libsass/sass2scss.cpp +834 -0
  87. data/ext/libsass/sass2scss.h +110 -0
  88. data/ext/libsass/sass_context.cpp +709 -0
  89. data/ext/libsass/sass_context.h +120 -0
  90. data/ext/libsass/sass_functions.cpp +137 -0
  91. data/ext/libsass/sass_functions.h +90 -0
  92. data/ext/libsass/sass_interface.cpp +277 -0
  93. data/ext/libsass/sass_interface.h +97 -0
  94. data/ext/libsass/sass_util.cpp +136 -0
  95. data/ext/libsass/sass_util.hpp +259 -0
  96. data/ext/libsass/sass_values.cpp +337 -0
  97. data/ext/libsass/sass_values.h +124 -0
  98. data/ext/libsass/script/bootstrap +10 -0
  99. data/ext/libsass/script/branding +10 -0
  100. data/ext/libsass/script/ci-build-libsass +72 -0
  101. data/ext/libsass/script/ci-install-compiler +4 -0
  102. data/ext/libsass/script/ci-install-deps +19 -0
  103. data/ext/libsass/script/ci-report-coverage +25 -0
  104. data/ext/libsass/script/coveralls-debug +32 -0
  105. data/ext/libsass/script/spec +5 -0
  106. data/ext/libsass/script/tap-driver +652 -0
  107. data/ext/libsass/script/tap-runner +1 -0
  108. data/ext/libsass/source_map.cpp +133 -0
  109. data/ext/libsass/source_map.hpp +46 -0
  110. data/ext/libsass/subset_map.hpp +145 -0
  111. data/ext/libsass/support/libsass.pc.in +11 -0
  112. data/ext/libsass/test-driver +127 -0
  113. data/ext/libsass/test/test_node.cpp +98 -0
  114. data/ext/libsass/test/test_paths.cpp +29 -0
  115. data/ext/libsass/test/test_selector_difference.cpp +28 -0
  116. data/ext/libsass/test/test_specificity.cpp +28 -0
  117. data/ext/libsass/test/test_subset_map.cpp +472 -0
  118. data/ext/libsass/test/test_superselector.cpp +71 -0
  119. data/ext/libsass/test/test_unification.cpp +33 -0
  120. data/ext/libsass/to_c.cpp +61 -0
  121. data/ext/libsass/to_c.hpp +44 -0
  122. data/ext/libsass/to_string.cpp +29 -0
  123. data/ext/libsass/to_string.hpp +32 -0
  124. data/ext/libsass/token.hpp +32 -0
  125. data/ext/libsass/units.cpp +54 -0
  126. data/ext/libsass/units.hpp +10 -0
  127. data/ext/libsass/utf8.h +34 -0
  128. data/ext/libsass/utf8/checked.h +327 -0
  129. data/ext/libsass/utf8/core.h +329 -0
  130. data/ext/libsass/utf8/unchecked.h +228 -0
  131. data/ext/libsass/utf8_string.cpp +102 -0
  132. data/ext/libsass/utf8_string.hpp +36 -0
  133. data/ext/libsass/util.cpp +189 -0
  134. data/ext/libsass/util.hpp +26 -0
  135. data/ext/libsass/win/libsass.filters +291 -0
  136. data/ext/libsass/win/libsass.sln +28 -0
  137. data/ext/libsass/win/libsass.vcxproj +255 -0
  138. data/lib/sassc.rb +6 -0
  139. data/lib/sassc/engine.rb +13 -0
  140. data/lib/sassc/native.rb +44 -0
  141. data/lib/sassc/native/native_context_api.rb +140 -0
  142. data/lib/sassc/native/native_functions_api.rb +41 -0
  143. data/lib/sassc/native/sass_input_style.rb +11 -0
  144. data/lib/sassc/native/sass_output_style.rb +10 -0
  145. data/lib/sassc/native/sass_value.rb +95 -0
  146. data/lib/sassc/native/string_list.rb +8 -0
  147. data/lib/sassc/version.rb +3 -0
  148. data/sassc.gemspec +43 -0
  149. data/test/smoke_test.rb +171 -0
  150. data/test/test_helper.rb +4 -0
  151. metadata +281 -0
@@ -0,0 +1,80 @@
1
+ #define SASS_EVAL
2
+
3
+ #include <iostream>
4
+
5
+ #ifndef SASS_OPERATION
6
+ #include "operation.hpp"
7
+ #endif
8
+
9
+ #ifndef SASS_ENVIRONMENT
10
+ #include "environment.hpp"
11
+ #endif
12
+
13
+ #ifndef SASS_POSITION
14
+ #include "position.hpp"
15
+ #endif
16
+
17
+ #include "sass_values.h"
18
+
19
+ namespace Sass {
20
+ using namespace std;
21
+
22
+ struct Context;
23
+ typedef Environment<AST_Node*> Env;
24
+ struct Backtrace;
25
+
26
+ class Eval : public Operation_CRTP<Expression*, Eval> {
27
+
28
+ Context& ctx;
29
+
30
+ Expression* fallback_impl(AST_Node* n);
31
+
32
+ public:
33
+ Env* env;
34
+ Backtrace* backtrace;
35
+ Eval(Context&, Env*, Backtrace*);
36
+ virtual ~Eval();
37
+ Eval* with(Env* e, Backtrace* bt); // for setting the env before eval'ing an expression
38
+ using Operation<Expression*>::operator();
39
+
40
+ // for evaluating function bodies
41
+ Expression* operator()(Block*);
42
+ Expression* operator()(Assignment*);
43
+ Expression* operator()(If*);
44
+ Expression* operator()(For*);
45
+ Expression* operator()(Each*);
46
+ Expression* operator()(While*);
47
+ Expression* operator()(Return*);
48
+ Expression* operator()(Warning*);
49
+ Expression* operator()(Error*);
50
+ Expression* operator()(Debug*);
51
+
52
+ Expression* operator()(List*);
53
+ Expression* operator()(Map*);
54
+ Expression* operator()(Binary_Expression*);
55
+ Expression* operator()(Unary_Expression*);
56
+ Expression* operator()(Function_Call*);
57
+ Expression* operator()(Function_Call_Schema*);
58
+ Expression* operator()(Variable*);
59
+ Expression* operator()(Textual*);
60
+ Expression* operator()(Number*);
61
+ Expression* operator()(Boolean*);
62
+ Expression* operator()(String_Schema*);
63
+ Expression* operator()(String_Constant*);
64
+ Expression* operator()(Media_Query*);
65
+ Expression* operator()(Media_Query_Expression*);
66
+ Expression* operator()(Feature_Query*);
67
+ Expression* operator()(Feature_Query_Condition*);
68
+ Expression* operator()(Null*);
69
+ Expression* operator()(Argument*);
70
+ Expression* operator()(Arguments*);
71
+
72
+ template <typename U>
73
+ Expression* fallback(U x) { return fallback_impl(x); }
74
+ };
75
+
76
+ Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, string path = "", Position position = Position());
77
+
78
+ bool eq(Expression*, Expression*, Context&);
79
+ bool lt(Expression*, Expression*, Context&);
80
+ }
@@ -0,0 +1,430 @@
1
+ #include "expand.hpp"
2
+ #include "bind.hpp"
3
+ #include "eval.hpp"
4
+ #include "contextualize.hpp"
5
+ #include "to_string.hpp"
6
+ #include "backtrace.hpp"
7
+
8
+ #include <iostream>
9
+ #include <typeinfo>
10
+
11
+ #ifndef SASS_CONTEXT
12
+ #include "context.hpp"
13
+ #endif
14
+
15
+ #include "parser.hpp"
16
+
17
+ namespace Sass {
18
+
19
+ Expand::Expand(Context& ctx, Eval* eval, Contextualize* contextualize, Env* env, Backtrace* bt)
20
+ : ctx(ctx),
21
+ eval(eval),
22
+ contextualize(contextualize),
23
+ env(env),
24
+ block_stack(vector<Block*>()),
25
+ property_stack(vector<String*>()),
26
+ selector_stack(vector<Selector*>()),
27
+ backtrace(bt)
28
+ { selector_stack.push_back(0); }
29
+
30
+ Statement* Expand::operator()(Block* b)
31
+ {
32
+ Env new_env;
33
+ new_env.link(*env);
34
+ env = &new_env;
35
+ Block* bb = new (ctx.mem) Block(b->path(), b->position(), b->length(), b->is_root());
36
+ block_stack.push_back(bb);
37
+ append_block(b);
38
+ block_stack.pop_back();
39
+ env = env->parent();
40
+ return bb;
41
+ }
42
+
43
+ Statement* Expand::operator()(Ruleset* r)
44
+ {
45
+ To_String to_string;
46
+ // if (selector_stack.back()) cerr << "expanding " << selector_stack.back()->perform(&to_string) << " and " << r->selector()->perform(&to_string) << endl;
47
+ Selector* sel_ctx = r->selector()->perform(contextualize->with(selector_stack.back(), env, backtrace));
48
+ // re-parse in order to restructure parent nodes correctly
49
+ sel_ctx = Parser::from_c_str((sel_ctx->perform(&to_string) + ";").c_str(), ctx, r->selector()->path(), r->selector()->position()).parse_selector_group();
50
+ selector_stack.push_back(sel_ctx);
51
+ Ruleset* rr = new (ctx.mem) Ruleset(r->path(),
52
+ r->position(),
53
+ sel_ctx,
54
+ r->block()->perform(this)->block());
55
+ selector_stack.pop_back();
56
+ return rr;
57
+ }
58
+
59
+ Statement* Expand::operator()(Propset* p)
60
+ {
61
+ property_stack.push_back(p->property_fragment());
62
+ Block* expanded_block = p->block()->perform(this)->block();
63
+
64
+ Block* current_block = block_stack.back();
65
+ for (size_t i = 0, L = expanded_block->length(); i < L; ++i) {
66
+ Statement* stm = (*expanded_block)[i];
67
+ if (typeid(*stm) == typeid(Declaration)) {
68
+ Declaration* dec = static_cast<Declaration*>(stm);
69
+ String_Schema* combined_prop = new (ctx.mem) String_Schema(p->path(), p->position());
70
+ if (!property_stack.empty()) {
71
+ *combined_prop << property_stack.back()
72
+ << new (ctx.mem) String_Constant(p->path(), p->position(), "-")
73
+ << dec->property(); // TODO: eval the prop into a string constant
74
+ }
75
+ else {
76
+ *combined_prop << dec->property();
77
+ }
78
+ dec->property(combined_prop);
79
+ *current_block << dec;
80
+ }
81
+ else {
82
+ error("contents of namespaced properties must result in style declarations only", stm->path(), stm->position(), backtrace);
83
+ }
84
+ }
85
+
86
+ property_stack.pop_back();
87
+
88
+ return 0;
89
+ }
90
+
91
+ Statement* Expand::operator()(Feature_Block* f)
92
+ {
93
+ Expression* feature_queries = f->feature_queries()->perform(eval->with(env, backtrace));
94
+ Feature_Block* ff = new (ctx.mem) Feature_Block(f->path(),
95
+ f->position(),
96
+ static_cast<Feature_Query*>(feature_queries),
97
+ f->block()->perform(this)->block());
98
+ ff->selector(selector_stack.back());
99
+ return ff;
100
+ }
101
+
102
+ Statement* Expand::operator()(Media_Block* m)
103
+ {
104
+ Expression* media_queries = m->media_queries()->perform(eval->with(env, backtrace));
105
+ Media_Block* mm = new (ctx.mem) Media_Block(m->path(),
106
+ m->position(),
107
+ static_cast<List*>(media_queries),
108
+ m->block()->perform(this)->block());
109
+ mm->selector(selector_stack.back());
110
+ return mm;
111
+ }
112
+
113
+ Statement* Expand::operator()(At_Rule* a)
114
+ {
115
+ Block* ab = a->block();
116
+ selector_stack.push_back(0);
117
+ Selector* as = a->selector();
118
+ Expression* av = a->value();
119
+ if (as) as = as->perform(contextualize->with(0, env, backtrace));
120
+ else if (av) av = av->perform(eval->with(env, backtrace));
121
+ Block* bb = ab ? ab->perform(this)->block() : 0;
122
+ At_Rule* aa = new (ctx.mem) At_Rule(a->path(),
123
+ a->position(),
124
+ a->keyword(),
125
+ as,
126
+ bb);
127
+ if (av) aa->value(av);
128
+ selector_stack.pop_back();
129
+ return aa;
130
+ }
131
+
132
+ Statement* Expand::operator()(Declaration* d)
133
+ {
134
+ String* old_p = d->property();
135
+ String* new_p = static_cast<String*>(old_p->perform(eval->with(env, backtrace)));
136
+ Expression* value = d->value()->perform(eval->with(env, backtrace));
137
+
138
+ if (value->is_invisible() && !d->is_important()) return 0;
139
+
140
+ return new (ctx.mem) Declaration(d->path(),
141
+ d->position(),
142
+ new_p,
143
+ value,
144
+ d->is_important());
145
+ }
146
+
147
+ Statement* Expand::operator()(Assignment* a)
148
+ {
149
+ string var(a->variable());
150
+ if (env->has(var)) {
151
+ Expression* v = static_cast<Expression*>((*env)[var]);
152
+ if (!a->is_guarded() || v->concrete_type() == Expression::NULL_VAL) (*env)[var] = a->value()->perform(eval->with(env, backtrace));
153
+ }
154
+ else {
155
+ env->current_frame()[var] = a->value()->perform(eval->with(env, backtrace));
156
+ }
157
+ return 0;
158
+ }
159
+
160
+ Statement* Expand::operator()(Import* imp)
161
+ {
162
+ Import* result = new (ctx.mem) Import(imp->path(), imp->position());
163
+ for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) {
164
+ result->urls().push_back(imp->urls()[i]->perform(eval->with(env, backtrace)));
165
+ }
166
+ return result;
167
+ }
168
+
169
+ Statement* Expand::operator()(Import_Stub* i)
170
+ {
171
+ append_block(ctx.style_sheets[i->file_name()]);
172
+ return 0;
173
+ }
174
+
175
+ Statement* Expand::operator()(Warning* w)
176
+ {
177
+ // eval handles this too, because warnings may occur in functions
178
+ w->perform(eval->with(env, backtrace));
179
+ return 0;
180
+ }
181
+
182
+ Statement* Expand::operator()(Error* e)
183
+ {
184
+ // eval handles this too, because errors may occur in functions
185
+ e->perform(eval->with(env, backtrace));
186
+ return 0;
187
+ }
188
+
189
+ Statement* Expand::operator()(Debug* d)
190
+ {
191
+ // eval handles this too, because warnings may occur in functions
192
+ d->perform(eval->with(env, backtrace));
193
+ return 0;
194
+ }
195
+
196
+ Statement* Expand::operator()(Comment* c)
197
+ {
198
+ // TODO: eval the text, once we're parsing/storing it as a String_Schema
199
+ return new (ctx.mem) Comment(c->path(), c->position(), static_cast<String*>(c->text()->perform(eval->with(env, backtrace))));
200
+ }
201
+
202
+ Statement* Expand::operator()(If* i)
203
+ {
204
+ if (*i->predicate()->perform(eval->with(env, backtrace))) {
205
+ append_block(i->consequent());
206
+ }
207
+ else {
208
+ Block* alt = i->alternative();
209
+ if (alt) append_block(alt);
210
+ }
211
+ return 0;
212
+ }
213
+
214
+ Statement* Expand::operator()(For* f)
215
+ {
216
+ string variable(f->variable());
217
+ Expression* low = f->lower_bound()->perform(eval->with(env, backtrace));
218
+ if (low->concrete_type() != Expression::NUMBER) {
219
+ error("lower bound of `@for` directive must be numeric", low->path(), low->position(), backtrace);
220
+ }
221
+ Expression* high = f->upper_bound()->perform(eval->with(env, backtrace));
222
+ if (high->concrete_type() != Expression::NUMBER) {
223
+ error("upper bound of `@for` directive must be numeric", high->path(), high->position(), backtrace);
224
+ }
225
+ double start = static_cast<Number*>(low)->value();
226
+ double end = static_cast<Number*>(high)->value();
227
+ Env new_env;
228
+ new_env[variable] = new (ctx.mem) Number(low->path(), low->position(), start);
229
+ new_env.link(env);
230
+ env = &new_env;
231
+ Block* body = f->block();
232
+ if (start < end) {
233
+ if (f->is_inclusive()) ++end;
234
+ for (double i = start;
235
+ i < end;
236
+ (*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), ++i)) {
237
+ append_block(body);
238
+ }
239
+ } else {
240
+ if (f->is_inclusive()) --end;
241
+ for (double i = start;
242
+ i > end;
243
+ (*env)[variable] = new (ctx.mem) Number(low->path(), low->position(), --i)) {
244
+ append_block(body);
245
+ }
246
+ }
247
+ env = new_env.parent();
248
+ return 0;
249
+ }
250
+
251
+ Statement* Expand::operator()(Each* e)
252
+ {
253
+ vector<string> variables(e->variables());
254
+ Expression* expr = e->list()->perform(eval->with(env, backtrace));
255
+ List* list = 0;
256
+ Map* map = 0;
257
+ if (expr->concrete_type() == Expression::MAP) {
258
+ map = static_cast<Map*>(expr);
259
+ }
260
+ else if (expr->concrete_type() != Expression::LIST) {
261
+ list = new (ctx.mem) List(expr->path(), expr->position(), 1, List::COMMA);
262
+ *list << expr;
263
+ }
264
+ else {
265
+ list = static_cast<List*>(expr);
266
+ }
267
+ Env new_env;
268
+ for (size_t i = 0, L = variables.size(); i < L; ++i) new_env[variables[i]] = 0;
269
+ new_env.link(env);
270
+ env = &new_env;
271
+ Block* body = e->block();
272
+
273
+ if (map) {
274
+ for (auto key : map->keys()) {
275
+ Expression* k = key->perform(eval->with(env, backtrace));
276
+ Expression* v = map->at(key)->perform(eval->with(env, backtrace));
277
+
278
+ if (variables.size() == 1) {
279
+ List* variable = new (ctx.mem) List(map->path(), map->position(), 2, List::SPACE);
280
+ *variable << k;
281
+ *variable << v;
282
+ (*env)[variables[0]] = variable;
283
+ } else {
284
+ (*env)[variables[0]] = k;
285
+ (*env)[variables[1]] = v;
286
+ }
287
+ append_block(body);
288
+ }
289
+ }
290
+ else {
291
+ for (size_t i = 0, L = list->length(); i < L; ++i) {
292
+ List* variable = 0;
293
+ if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
294
+ variable = new (ctx.mem) List((*list)[i]->path(), (*list)[i]->position(), 1, List::COMMA);
295
+ *variable << (*list)[i];
296
+ }
297
+ else {
298
+ variable = static_cast<List*>((*list)[i]);
299
+ }
300
+ for (size_t j = 0, K = variables.size(); j < K; ++j) {
301
+ if (j < variable->length()) {
302
+ (*env)[variables[j]] = (*variable)[j]->perform(eval->with(env, backtrace));
303
+ }
304
+ else {
305
+ (*env)[variables[j]] = new (ctx.mem) Null(expr->path(), expr->position());
306
+ }
307
+ }
308
+ append_block(body);
309
+ }
310
+ }
311
+ env = new_env.parent();
312
+ return 0;
313
+ }
314
+
315
+ Statement* Expand::operator()(While* w)
316
+ {
317
+ Expression* pred = w->predicate();
318
+ Block* body = w->block();
319
+ while (*pred->perform(eval->with(env, backtrace))) {
320
+ append_block(body);
321
+ }
322
+ return 0;
323
+ }
324
+
325
+ Statement* Expand::operator()(Return* r)
326
+ {
327
+ error("@return may only be used within a function", r->path(), r->position(), backtrace);
328
+ return 0;
329
+ }
330
+
331
+ Statement* Expand::operator()(Extension* e)
332
+ {
333
+ To_String to_string;
334
+ Selector_List* extender = static_cast<Selector_List*>(selector_stack.back());
335
+ if (!extender) return 0;
336
+ Selector_List* extendee = static_cast<Selector_List*>(e->selector()->perform(contextualize->with(0, env, backtrace)));
337
+ if (extendee->length() != 1) {
338
+ error("selector groups may not be extended", extendee->path(), extendee->position(), backtrace);
339
+ }
340
+ Complex_Selector* c = (*extendee)[0];
341
+ if (!c->head() || c->tail()) {
342
+ error("nested selectors may not be extended", c->path(), c->position(), backtrace);
343
+ }
344
+ Compound_Selector* s = c->head();
345
+
346
+ // // need to convert the compound selector into a by-value data structure
347
+ // vector<string> target_vec;
348
+ // for (size_t i = 0, L = s->length(); i < L; ++i)
349
+ // { target_vec.push_back((*s)[i]->perform(&to_string)); }
350
+
351
+ for (size_t i = 0, L = extender->length(); i < L; ++i) {
352
+ // let's test this out
353
+ // cerr << "REGISTERING EXTENSION REQUEST: " << (*extender)[i]->perform(&to_string) << " <- " << s->perform(&to_string) << endl;
354
+ ctx.subset_map.put(s->to_str_vec(), make_pair((*extender)[i], s));
355
+ }
356
+ return 0;
357
+ }
358
+
359
+ Statement* Expand::operator()(Definition* d)
360
+ {
361
+ Definition* dd = new (ctx.mem) Definition(*d);
362
+ env->current_frame()[d->name() +
363
+ (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd;
364
+ // set the static link so we can have lexical scoping
365
+ dd->environment(env);
366
+ return 0;
367
+ }
368
+
369
+ Statement* Expand::operator()(Mixin_Call* c)
370
+ {
371
+ string full_name(c->name() + "[m]");
372
+ if (!env->has(full_name)) {
373
+ error("no mixin named " + c->name(), c->path(), c->position(), backtrace);
374
+ }
375
+ Definition* def = static_cast<Definition*>((*env)[full_name]);
376
+ Block* body = def->block();
377
+ Parameters* params = def->parameters();
378
+ Arguments* args = static_cast<Arguments*>(c->arguments()
379
+ ->perform(eval->with(env, backtrace)));
380
+ Backtrace here(backtrace, c->path(), c->position(), ", in mixin `" + c->name() + "`");
381
+ backtrace = &here;
382
+ Env new_env;
383
+ new_env.link(def->environment());
384
+ if (c->block()) {
385
+ // represent mixin content blocks as thunks/closures
386
+ Definition* thunk = new (ctx.mem) Definition(c->path(),
387
+ c->position(),
388
+ "@content",
389
+ new (ctx.mem) Parameters(c->path(), c->position()),
390
+ c->block(),
391
+ Definition::MIXIN);
392
+ thunk->environment(env);
393
+ new_env.current_frame()["@content[m]"] = thunk;
394
+ }
395
+ bind("mixin " + c->name(), params, args, ctx, &new_env, eval);
396
+ Env* old_env = env;
397
+ env = &new_env;
398
+ append_block(body);
399
+ env = old_env;
400
+ backtrace = here.parent;
401
+ return 0;
402
+ }
403
+
404
+ Statement* Expand::operator()(Content* c)
405
+ {
406
+ // convert @content directives into mixin calls to the underlying thunk
407
+ if (!env->has("@content[m]")) return 0;
408
+ Mixin_Call* call = new (ctx.mem) Mixin_Call(c->path(),
409
+ c->position(),
410
+ "@content",
411
+ new (ctx.mem) Arguments(c->path(), c->position()));
412
+ return call->perform(this);
413
+ }
414
+
415
+ inline Statement* Expand::fallback_impl(AST_Node* n)
416
+ {
417
+ error("unknown internal error; please contact the LibSass maintainers", n->path(), n->position(), backtrace);
418
+ String_Constant* msg = new (ctx.mem) String_Constant("", Position(), string("`Expand` doesn't handle ") + typeid(*n).name());
419
+ return new (ctx.mem) Warning("", Position(), msg);
420
+ }
421
+
422
+ inline void Expand::append_block(Block* b)
423
+ {
424
+ Block* current_block = block_stack.back();
425
+ for (size_t i = 0, L = b->length(); i < L; ++i) {
426
+ Statement* ith = (*b)[i]->perform(this);
427
+ if (ith) *current_block << ith;
428
+ }
429
+ }
430
+ }