Skip to content

Commit 1f709b8

Browse files
committed
Fix error for multiplication of invalid units
Fixes minor bug when parsing numbers like `2/px`
1 parent f50781a commit 1f709b8

File tree

7 files changed

+45
-18
lines changed

7 files changed

+45
-18
lines changed

src/ast.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -960,8 +960,10 @@ namespace Sass {
960960
while (true) {
961961
r = u.find_first_of("*/", l);
962962
string unit(u.substr(l, r == string::npos ? r : r - l));
963-
if (nominator) numerator_units_.push_back(unit);
964-
else denominator_units_.push_back(unit);
963+
if (!unit.empty()) {
964+
if (nominator) numerator_units_.push_back(unit);
965+
else denominator_units_.push_back(unit);
966+
}
965967
if (r == string::npos) break;
966968
// ToDo: should error for multiple slashes
967969
// if (!nominator && u[r] == '/') error(...)
@@ -991,7 +993,7 @@ namespace Sass {
991993
bool Number::is_unitless()
992994
{ return numerator_units_.empty() && denominator_units_.empty(); }
993995

994-
void Number::normalize(const string& prefered)
996+
void Number::normalize(const string& prefered, bool strict)
995997
{
996998

997999
// first make sure same units cancel each other out
@@ -1035,7 +1037,7 @@ namespace Sass {
10351037
if (string_to_unit(nom) == UNKNOWN) continue;
10361038
// we now have two convertable units
10371039
// add factor for current conversion
1038-
factor *= conversion_factor(nom, denom);
1040+
factor *= conversion_factor(nom, denom, strict);
10391041
// update nominator/denominator exponent
10401042
-- exponents[nom]; ++ exponents[denom];
10411043
// inner loop done
@@ -1056,8 +1058,10 @@ namespace Sass {
10561058
{
10571059
// opted to have these switches in the inner loop
10581060
// makes it more readable and should not cost much
1059-
if (exp.second < 0) denominator_units_.push_back(exp.first);
1060-
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1061+
if (!exp.first.empty()) {
1062+
if (exp.second < 0) denominator_units_.push_back(exp.first);
1063+
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1064+
}
10611065
}
10621066
}
10631067

@@ -1067,14 +1071,14 @@ namespace Sass {
10671071

10681072
// maybe convert to other unit
10691073
// easier implemented on its own
1070-
try { convert(prefered); }
1074+
try { convert(prefered, strict); }
10711075
catch (incompatibleUnits& err)
10721076
{ error(err.what(), pstate()); }
10731077
catch (...) { throw; }
10741078

10751079
}
10761080

1077-
void Number::convert(const string& prefered)
1081+
void Number::convert(const string& prefered, bool strict)
10781082
{
10791083
// abort if unit is empty
10801084
if (prefered.empty()) return;
@@ -1109,7 +1113,7 @@ namespace Sass {
11091113
if (string_to_unit(denom) == UNKNOWN) continue;
11101114
// we now have two convertable units
11111115
// add factor for current conversion
1112-
factor *= conversion_factor(denom, prefered);
1116+
factor *= conversion_factor(denom, prefered, strict);
11131117
// update nominator/denominator exponent
11141118
++ exponents[denom]; -- exponents[prefered];
11151119
}
@@ -1130,7 +1134,7 @@ namespace Sass {
11301134
if (string_to_unit(nom) == UNKNOWN) continue;
11311135
// we now have two convertable units
11321136
// add factor for current conversion
1133-
factor *= conversion_factor(nom, prefered);
1137+
factor *= conversion_factor(nom, prefered, strict);
11341138
// update nominator/denominator exponent
11351139
-- exponents[nom]; ++ exponents[prefered];
11361140
}
@@ -1148,8 +1152,10 @@ namespace Sass {
11481152
{
11491153
// opted to have these switches in the inner loop
11501154
// makes it more readable and should not cost much
1151-
if (exp.second < 0) denominator_units_.push_back(exp.first);
1152-
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1155+
if (!exp.first.empty()) {
1156+
if (exp.second < 0) denominator_units_.push_back(exp.first);
1157+
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1158+
}
11531159
}
11541160
}
11551161

src/ast.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,8 +1193,8 @@ namespace Sass {
11931193
string unit() const;
11941194

11951195
bool is_unitless();
1196-
void convert(const string& unit = "");
1197-
void normalize(const string& unit = "");
1196+
void convert(const string& unit = "", bool strict = false);
1197+
void normalize(const string& unit = "", bool strict = false);
11981198
// useful for making one number compatible with another
11991199
string find_convertible_unit() const;
12001200

src/eval.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,8 @@ namespace Sass {
11181118
}
11191119

11201120
Number tmp(r);
1121-
tmp.normalize(l.find_convertible_unit());
1121+
bool strict = op != Sass_OP::MUL && op != Sass_OP::DIV;
1122+
tmp.normalize(l.find_convertible_unit(), strict);
11221123
string l_unit(l.unit());
11231124
string r_unit(tmp.unit());
11241125
if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&

src/output.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ namespace Sass {
1818
return n->perform(this);
1919
}
2020

21+
void Output::operator()(Number* n)
22+
{
23+
// use values to_string facility
24+
To_String to_string(ctx);
25+
string res = n->perform(&to_string);
26+
// check for a valid unit here
27+
// includes result for reporting
28+
if (n->numerator_units().size() > 1 ||
29+
n->denominator_units().size() > 0 ||
30+
(n->numerator_units().size() && n->numerator_units()[0].find_first_of('/') != string::npos) ||
31+
(n->numerator_units().size() && n->numerator_units()[0].find_first_of('*') != string::npos)
32+
) {
33+
error(res + " isn't a valid CSS value.", n->pstate());
34+
}
35+
// output the final token
36+
append_token(res, n);
37+
}
38+
2139
void Output::operator()(Import* imp)
2240
{
2341
top_nodes.push_back(imp);

src/output.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ namespace Sass {
4444
virtual void operator()(Keyframe_Rule*);
4545
virtual void operator()(Import*);
4646
virtual void operator()(Comment*);
47+
virtual void operator()(Number*);
4748
virtual void operator()(String_Quoted*);
4849
virtual void operator()(String_Constant*);
4950

src/units.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ namespace Sass {
120120
}
121121

122122
// throws incompatibleUnits exceptions
123-
double conversion_factor(const string& s1, const string& s2)
123+
double conversion_factor(const string& s1, const string& s2, bool strict)
124124
{
125125
// assert for same units
126126
if (s1 == s2) return 1;
@@ -135,7 +135,8 @@ namespace Sass {
135135
size_t i1 = u1 - t1;
136136
size_t i2 = u2 - t2;
137137
// error if units are not of the same group
138-
if (t1 != t2) throw incompatibleUnits(u1, u2);
138+
// don't error for multiplication and division
139+
if (strict && t1 != t2) throw incompatibleUnits(u1, u2);
139140
// only process known units
140141
if (u1 != UNKNOWN && u2 != UNKNOWN) {
141142
switch (t1) {

src/units.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ namespace Sass {
6767
const char* unit_to_string(SassUnit unit);
6868
enum SassUnitType get_unit_type(SassUnit unit);
6969
// throws incompatibleUnits exceptions
70-
double conversion_factor(const string&, const string&);
70+
double conversion_factor(const string&, const string&, bool = true);
7171

7272
class incompatibleUnits: public exception
7373
{

0 commit comments

Comments
 (0)