sassc 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -249,16 +249,16 @@ namespace Sass {
249
249
  h = s = 0; // achromatic
250
250
  }
251
251
  else {
252
- if (l < 0.5) s = del / (2.0 * l);
253
- else s = del / (2.0 - 2.0 * l);
252
+ if (l < 0.5) s = del / (max + min);
253
+ else s = del / (2.0 - max - min);
254
254
 
255
- if (r == max) h = 60 * (g - b) / del;
256
- else if (g == max) h = 60 * (b - r) / del + 120;
257
- else if (b == max) h = 60 * (r - g) / del + 240;
255
+ if (r == max) h = (g - b) / del + (g < b ? 6 : 0);
256
+ else if (g == max) h = (b - r) / del + 2;
257
+ else if (b == max) h = (r - g) / del + 4;
258
258
  }
259
259
 
260
260
  HSL hsl_struct;
261
- hsl_struct.h = h;
261
+ hsl_struct.h = h / 6 * 360;
262
262
  hsl_struct.s = s * 100;
263
263
  hsl_struct.l = l * 100;
264
264
 
@@ -281,11 +281,18 @@ namespace Sass {
281
281
  s /= 100.0;
282
282
  l /= 100.0;
283
283
 
284
+ if (l < 0) l = 0;
285
+ if (s < 0) s = 0;
286
+ if (l > 1) l = 1;
287
+ if (s > 1) s = 1;
288
+ while (h < 0) h += 1;
289
+ while (h > 1) h -= 1;
290
+
284
291
  // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
285
292
  double m2;
286
293
  if (l <= 0.5) m2 = l*(s+1.0);
287
294
  else m2 = (l+s)-(l*s);
288
- double m1 = (l*2)-m2;
295
+ double m1 = (l*2.0)-m2;
289
296
  // round the results -- consider moving this into the Color constructor
290
297
  double r = (h_to_rgb(m1, m2, h+1.0/3.0) * 255.0);
291
298
  double g = (h_to_rgb(m1, m2, h) * 255.0);
@@ -760,15 +767,18 @@ namespace Sass {
760
767
  Signature unquote_sig = "unquote($string)";
761
768
  BUILT_IN(sass_unquote)
762
769
  {
763
- To_String to_string(&ctx);
764
770
  AST_Node* arg = env["$string"];
765
- if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
771
+ if (dynamic_cast<Null*>(arg)) {
772
+ return new (ctx.mem) Null(pstate);
773
+ }
774
+ else if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
766
775
  String_Constant* result = new (ctx.mem) String_Constant(pstate, string_quoted->value());
767
776
  // remember if the string was quoted (color tokens)
768
777
  result->sass_fix_1291(string_quoted->quote_mark() != 0);
769
778
  return result;
770
779
  }
771
- return new (ctx.mem) String_Constant(pstate, string(arg->perform(&to_string)));
780
+ To_String to_string(&ctx);
781
+ return new (ctx.mem) String_Constant(pstate, unquote(string(arg->perform(&to_string))));
772
782
  }
773
783
 
774
784
  Signature quote_sig = "quote($string)";
@@ -906,28 +916,25 @@ namespace Sass {
906
916
  string newstr;
907
917
  try {
908
918
  String_Constant* s = ARG("$string", String_Constant);
909
- Number* n = ARG("$start-at", Number);
910
- Number* m = ARG("$end-at", Number);
919
+ double start_at = ARG("$start-at", Number)->value();
920
+ double end_at = ARG("$end-at", Number)->value();
911
921
 
912
922
  string str = unquote(s->value());
913
923
 
914
- // normalize into 0-based indices
915
- size_t start = UTF_8::offset_at_position(str, UTF_8::normalize_index(static_cast<int>(n->value()), UTF_8::code_point_count(str)));
916
- size_t end = UTF_8::offset_at_position(str, UTF_8::normalize_index(static_cast<int>(m->value()), UTF_8::code_point_count(str)));
917
-
918
- // `str-slice` should always return an empty string when $end-at == 0
919
- // `normalize_index` normalizes 1 -> 0 so we need to check the original value
920
- if(m->value() == 0) {
921
- if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
922
- if(!ss->quote_mark()) return new (ctx.mem) Null(pstate);
923
- } else {
924
- return new (ctx.mem) Null(pstate);
925
- }
926
- newstr = "";
927
- } else if(start == end && m->value() != 0) {
928
- newstr = str.substr(start, 1);
929
- } else if(end > start) {
930
- newstr = str.substr(start, end - start + UTF_8::code_point_size_at_offset(str, end));
924
+ size_t size = utf8::distance(str.begin(), str.end());
925
+ if (end_at <= size * -1.0) { end_at += size; }
926
+ if (end_at < 0) { end_at += size + 1; }
927
+ if (end_at > size) { end_at = size; }
928
+ if (start_at < 0) { start_at += size + 1; }
929
+ else if (start_at == 0) { ++ start_at; }
930
+
931
+ if (start_at <= end_at)
932
+ {
933
+ string::iterator start = str.begin();
934
+ utf8::advance(start, start_at - 1, str.end());
935
+ string::iterator end = start;
936
+ utf8::advance(end, end_at - start_at + 1, str.end());
937
+ newstr = string(start, end);
931
938
  }
932
939
  if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
933
940
  if(ss->quote_mark()) newstr = quote(newstr);
@@ -1244,13 +1251,6 @@ namespace Sass {
1244
1251
  return zippers;
1245
1252
  }
1246
1253
 
1247
- Signature compact_sig = "compact($values...)";
1248
- BUILT_IN(compact)
1249
- {
1250
- error("`compact` has been removed from libsass because it's not part of the Sass spec", pstate);
1251
- return 0; // suppress warning, error will exit anyway
1252
- }
1253
-
1254
1254
  Signature list_separator_sig = "list_separator($list)";
1255
1255
  BUILT_IN(list_separator)
1256
1256
  {
@@ -1471,7 +1471,7 @@ namespace Sass {
1471
1471
  for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1472
1472
  Expression* expr = arglist->value_at_index(i);
1473
1473
  if (arglist->is_arglist()) {
1474
- Argument* arg = static_cast<Argument*>(expr);
1474
+ Argument* arg = static_cast<Argument*>((*arglist)[i]);
1475
1475
  *args << new (ctx.mem) Argument(pstate,
1476
1476
  expr,
1477
1477
  "",
@@ -78,7 +78,6 @@ namespace Sass {
78
78
  extern Signature join_sig;
79
79
  extern Signature append_sig;
80
80
  extern Signature zip_sig;
81
- extern Signature compact_sig;
82
81
  extern Signature list_separator_sig;
83
82
  extern Signature type_of_sig;
84
83
  extern Signature unit_sig;
@@ -153,7 +152,6 @@ namespace Sass {
153
152
  BUILT_IN(join);
154
153
  BUILT_IN(append);
155
154
  BUILT_IN(zip);
156
- BUILT_IN(compact);
157
155
  BUILT_IN(list_separator);
158
156
  BUILT_IN(type_of);
159
157
  BUILT_IN(unit);
@@ -416,6 +416,7 @@ namespace Sass {
416
416
 
417
417
  void Inspect::operator()(Number* n)
418
418
  {
419
+ n->normalize();
419
420
  stringstream ss;
420
421
  ss.precision(ctx ? ctx->precision : 5);
421
422
  ss << fixed << n->value();
@@ -424,8 +425,11 @@ namespace Sass {
424
425
  // if after applying precsision, the value gets
425
426
  // truncated to zero, sass emits 0.0 instead of 0
426
427
  bool nonzero = n->value() != 0;
427
- for (size_t i = d.length()-1; d[i] == '0'; --i) {
428
- d.resize(d.length()-1);
428
+ size_t decimal = d.find('.');
429
+ if (decimal != string::npos) {
430
+ for (size_t i = d.length()-1; d[i] == '0' && i >= decimal; --i) {
431
+ d.resize(d.length()-1);
432
+ }
429
433
  }
430
434
  if (d[d.length()-1] == '.') d.resize(d.length()-1);
431
435
  if (n->numerator_units().size() > 1 ||
@@ -444,6 +448,9 @@ namespace Sass {
444
448
  // use fractional output if we had
445
449
  // a value before it got truncated
446
450
  if (d == "0" && nonzero) d = "0.0";
451
+ // if the precision is 0 sass cast
452
+ // casts to a float with precision 1
453
+ if (ctx->precision == 0) d += ".0";
447
454
  // append number and unit
448
455
  append_token(d + n->unit(), n);
449
456
  }
@@ -8,8 +8,7 @@ namespace Sass {
8
8
  Output::Output(Context* ctx)
9
9
  : Inspect(Emitter(ctx)),
10
10
  charset(""),
11
- top_imports(0),
12
- top_comments(0)
11
+ top_nodes(0)
13
12
  {}
14
13
 
15
14
  Output::~Output() { }
@@ -21,7 +20,7 @@ namespace Sass {
21
20
 
22
21
  void Output::operator()(Import* imp)
23
22
  {
24
- top_imports.push_back(imp);
23
+ top_nodes.push_back(imp);
25
24
  }
26
25
 
27
26
  OutputBuffer Output::get_buffer(void)
@@ -30,15 +29,9 @@ namespace Sass {
30
29
  Emitter emitter(ctx);
31
30
  Inspect inspect(emitter);
32
31
 
33
- size_t size_com = top_comments.size();
34
- for (size_t i = 0; i < size_com; i++) {
35
- top_comments[i]->perform(&inspect);
36
- inspect.append_mandatory_linefeed();
37
- }
38
-
39
- size_t size_imp = top_imports.size();
40
- for (size_t i = 0; i < size_imp; i++) {
41
- top_imports[i]->perform(&inspect);
32
+ size_t size_nodes = top_nodes.size();
33
+ for (size_t i = 0; i < size_nodes; i++) {
34
+ top_nodes[i]->perform(&inspect);
42
35
  inspect.append_mandatory_linefeed();
43
36
  }
44
37
 
@@ -79,8 +72,8 @@ namespace Sass {
79
72
  // if (indentation && txt == "/**/") return;
80
73
  bool important = c->is_important();
81
74
  if (output_style() != COMPRESSED || important) {
82
- if (buffer().size() + top_imports.size() == 0) {
83
- top_comments.push_back(c);
75
+ if (buffer().size() == 0) {
76
+ top_nodes.push_back(c);
84
77
  } else {
85
78
  in_comment = true;
86
79
  append_indentation();
@@ -30,8 +30,7 @@ namespace Sass {
30
30
 
31
31
  protected:
32
32
  string charset;
33
- vector<Import*> top_imports;
34
- vector<Comment*> top_comments;
33
+ vector<AST_Node*> top_nodes;
35
34
 
36
35
  public:
37
36
  OutputBuffer get_buffer(void);
@@ -1396,7 +1396,8 @@ namespace Sass {
1396
1396
  Token str(lexed);
1397
1397
  --str.end;
1398
1398
  --position;
1399
- String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
1399
+
1400
+ String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str.time_wspace());
1400
1401
  // str_node->is_delayed(true);
1401
1402
  return str_node;
1402
1403
  }
@@ -1414,6 +1415,7 @@ namespace Sass {
1414
1415
  Token str(lexed);
1415
1416
  const char* i = str.begin;
1416
1417
  // see if there any interpolants
1418
+ const char* q;
1417
1419
  const char* p = find_first_in_interval< exactly<hash_lbrace> >(str.begin, str.end);
1418
1420
  if (!p) {
1419
1421
  String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
@@ -1423,8 +1425,16 @@ namespace Sass {
1423
1425
 
1424
1426
  String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1425
1427
  while (i < str.end) {
1428
+ q = find_first_in_interval< alternatives< exactly<'"'>, exactly<'\''> > >(i, str.end);
1426
1429
  p = find_first_in_interval< exactly<hash_lbrace> >(i, str.end);
1427
- if (p) {
1430
+ if (q && (!p || p > q)) {
1431
+ if (i < q) {
1432
+ (*schema) << new (ctx.mem) String_Constant(pstate, string(i, q)); // accumulate the preceding segment if it's nonempty
1433
+ }
1434
+ (*schema) << new (ctx.mem) String_Constant(pstate, string(q, q+1)); // capture the quote mark separately
1435
+ i = q+1;
1436
+ }
1437
+ else if (p) {
1428
1438
  if (i < p) {
1429
1439
  (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
1430
1440
  }
@@ -1498,7 +1508,7 @@ namespace Sass {
1498
1508
  (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
1499
1509
  }
1500
1510
  else if (lex< quoted_string >()) {
1501
- (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
1511
+ (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1502
1512
  }
1503
1513
  else if (lex< variable >()) {
1504
1514
  (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
@@ -1609,8 +1619,10 @@ namespace Sass {
1609
1619
  {
1610
1620
  lex< identifier >();
1611
1621
  string name(lexed);
1622
+
1623
+ ParserState call_pos = pstate;
1612
1624
  Arguments* args = parse_arguments(name == "url");
1613
- return new (ctx.mem) Function_Call(pstate, name, args);
1625
+ return new (ctx.mem) Function_Call(call_pos, name, args);
1614
1626
  }
1615
1627
 
1616
1628
  Function_Call_Schema* Parser::parse_function_call_schema()
@@ -89,6 +89,11 @@ namespace Sass {
89
89
  size_t length() const { return end - begin; }
90
90
  string ws_before() const { return string(prefix, begin); }
91
91
  string to_string() const { return string(begin, end); }
92
+ string time_wspace() const {
93
+ string str(to_string());
94
+ string whitespaces(" \t\f\v\n\r");
95
+ return str.erase(str.find_last_not_of(whitespaces)+1);
96
+ }
92
97
 
93
98
  operator bool() { return begin && end && begin >= end; }
94
99
  operator string() { return to_string(); }
@@ -710,7 +710,10 @@ namespace Sass {
710
710
  }
711
711
 
712
712
  const char* static_value(const char* src) {
713
- return sequence< static_component,
713
+ return sequence< sequence<
714
+ static_component,
715
+ zero_plus< identifier >
716
+ >,
714
717
  zero_plus < sequence<
715
718
  alternatives<
716
719
  sequence< optional_spaces, alternatives<
@@ -722,6 +725,7 @@ namespace Sass {
722
725
  >,
723
726
  static_component
724
727
  > >,
728
+ optional_css_whitespace,
725
729
  alternatives< exactly<';'>, exactly<'}'> >
726
730
  >(src);
727
731
  }
@@ -38,6 +38,7 @@ extern "C" {
38
38
 
39
39
  struct Sass_String {
40
40
  enum Sass_Tag tag;
41
+ bool quoted;
41
42
  char* value;
42
43
  };
43
44
 
@@ -110,6 +111,8 @@ extern "C" {
110
111
  // Getters and setters for Sass_String
111
112
  const char* ADDCALL sass_string_get_value(const union Sass_Value* v) { return v->string.value; }
112
113
  void ADDCALL sass_string_set_value(union Sass_Value* v, char* value) { v->string.value = value; }
114
+ const bool ADDCALL sass_string_is_quoted(const union Sass_Value* v) { return v->string.quoted; }
115
+ void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted) { v->string.quoted = quoted; }
113
116
 
114
117
  // Getters and setters for Sass_Boolean
115
118
  bool ADDCALL sass_boolean_get_value(const union Sass_Value* v) { return v->boolean.value; }
@@ -187,6 +190,18 @@ extern "C" {
187
190
  {
188
191
  Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
189
192
  if (v == 0) return 0;
193
+ v->string.quoted = false;
194
+ v->string.tag = SASS_STRING;
195
+ v->string.value = val ? sass_strdup(val) : 0;
196
+ if (v->string.value == 0) { free(v); return 0; }
197
+ return v;
198
+ }
199
+
200
+ union Sass_Value* ADDCALL sass_make_qstring(const char* val)
201
+ {
202
+ Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
203
+ if (v == 0) return 0;
204
+ v->string.quoted = true;
190
205
  v->string.tag = SASS_STRING;
191
206
  v->string.value = val ? sass_strdup(val) : 0;
192
207
  if (v->string.value == 0) { free(v); return 0; }
@@ -57,6 +57,8 @@ ADDAPI void ADDCALL sass_number_set_unit (union Sass_Value* v, char* unit);
57
57
  // Getters and setters for Sass_String
58
58
  ADDAPI const char* ADDCALL sass_string_get_value (const union Sass_Value* v);
59
59
  ADDAPI void ADDCALL sass_string_set_value (union Sass_Value* v, char* value);
60
+ ADDAPI const bool ADDCALL sass_string_is_quoted(const union Sass_Value* v);
61
+ ADDAPI void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted);
60
62
 
61
63
  // Getters and setters for Sass_Boolean
62
64
  ADDAPI bool ADDCALL sass_boolean_get_value (const union Sass_Value* v);
@@ -101,6 +103,7 @@ ADDAPI void ADDCALL sass_warning_set_message (union Sass_Value* v, char* msg);
101
103
  ADDAPI union Sass_Value* ADDCALL sass_make_null (void);
102
104
  ADDAPI union Sass_Value* ADDCALL sass_make_boolean (bool val);
103
105
  ADDAPI union Sass_Value* ADDCALL sass_make_string (const char* val);
106
+ ADDAPI union Sass_Value* ADDCALL sass_make_qstring (const char* val);
104
107
  ADDAPI union Sass_Value* ADDCALL sass_make_number (double val, const char* unit);
105
108
  ADDAPI union Sass_Value* ADDCALL sass_make_color (double r, double g, double b, double a);
106
109
  ADDAPI union Sass_Value* ADDCALL sass_make_list (size_t len, enum Sass_Separator sep);
@@ -44,6 +44,59 @@ namespace Sass {
44
44
  return atof(str);
45
45
  }
46
46
 
47
+ string string_eval_escapes(const string& s)
48
+ {
49
+
50
+ string out("");
51
+ bool esc = false;
52
+ for (size_t i = 0, L = s.length(); i < L; ++i) {
53
+ if(s[i] == '\\' && esc == false) {
54
+ esc = true;
55
+
56
+ // escape length
57
+ size_t len = 1;
58
+
59
+ // parse as many sequence chars as possible
60
+ // ToDo: Check if ruby aborts after possible max
61
+ while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
62
+
63
+ // hex string?
64
+ if (len > 1) {
65
+
66
+ // convert the extracted hex string to code point value
67
+ // ToDo: Maybe we could do this without creating a substring
68
+ uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), nullptr, 16);
69
+
70
+ if (cp == 0) cp = 0xFFFD;
71
+
72
+ // assert invalid code points
73
+ if (cp >= 1) {
74
+
75
+ // use a very simple approach to convert via utf8 lib
76
+ // maybe there is a more elegant way; maybe we shoud
77
+ // convert the whole output from string to a stream!?
78
+ // allocate memory for utf8 char and convert to utf8
79
+ unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
80
+ for(size_t m = 0; u[m] && m < 5; m++) out.push_back(u[m]);
81
+
82
+ // skip some more chars?
83
+ i += len - 1; esc = false;
84
+ if (cp == 10) out += ' ';
85
+
86
+ }
87
+
88
+ }
89
+
90
+ }
91
+ else {
92
+ out += s[i];
93
+ esc = false;
94
+ }
95
+ }
96
+ return out;
97
+
98
+ }
99
+
47
100
  // double escape every escape sequences
48
101
  // escape unescaped quotes and backslashes
49
102
  string string_escape(const string& str)
@@ -177,6 +230,7 @@ namespace Sass {
177
230
  {
178
231
  string str = "";
179
232
  size_t has = 0;
233
+ char prev = 0;
180
234
  bool clean = false;
181
235
  for (auto i : text) {
182
236
  if (clean) {
@@ -188,7 +242,8 @@ namespace Sass {
188
242
  else {
189
243
  clean = false;
190
244
  str += ' ';
191
- str += i;
245
+ if (prev == '*' && i == '/') str += "*/";
246
+ else str += i;
192
247
  }
193
248
  } else if (i == '\n') {
194
249
  clean = true;
@@ -197,6 +252,7 @@ namespace Sass {
197
252
  } else {
198
253
  str += i;
199
254
  }
255
+ prev = i;
200
256
  }
201
257
  if (has) return str;
202
258
  else return text;
@@ -327,12 +383,12 @@ namespace Sass {
327
383
  }
328
384
  // check for unexpected delimiter
329
385
  // be strict and throw error back
330
- else if (!skipped && q == s[i]) {
331
- // don't be that strict
332
- return s;
333
- // this basically always means an internal error and not users fault
334
- error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]"));
335
- }
386
+ // else if (!skipped && q == s[i]) {
387
+ // // don't be that strict
388
+ // return s;
389
+ // // this basically always means an internal error and not users fault
390
+ // error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]"));
391
+ // }
336
392
  else {
337
393
  skipped = false;
338
394
  unq.push_back(s[i]);