Skip to content

Commit 666d2c0

Browse files
committed
Merge pull request #1342 from mgreter/feature/number-fixes
Fix error for multiplication of invalid units
2 parents e154e5c + 1f709b8 commit 666d2c0

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
@@ -1256,8 +1256,10 @@ namespace Sass {
12561256
while (true) {
12571257
r = u.find_first_of("*/", l);
12581258
string unit(u.substr(l, r == string::npos ? r : r - l));
1259-
if (nominator) numerator_units_.push_back(unit);
1260-
else denominator_units_.push_back(unit);
1259+
if (!unit.empty()) {
1260+
if (nominator) numerator_units_.push_back(unit);
1261+
else denominator_units_.push_back(unit);
1262+
}
12611263
if (r == string::npos) break;
12621264
// ToDo: should error for multiple slashes
12631265
// if (!nominator && u[r] == '/') error(...)
@@ -1287,7 +1289,7 @@ namespace Sass {
12871289
bool Number::is_unitless()
12881290
{ return numerator_units_.empty() && denominator_units_.empty(); }
12891291

1290-
void Number::normalize(const string& prefered)
1292+
void Number::normalize(const string& prefered, bool strict)
12911293
{
12921294

12931295
// first make sure same units cancel each other out
@@ -1331,7 +1333,7 @@ namespace Sass {
13311333
if (string_to_unit(nom) == UNKNOWN) continue;
13321334
// we now have two convertable units
13331335
// add factor for current conversion
1334-
factor *= conversion_factor(nom, denom);
1336+
factor *= conversion_factor(nom, denom, strict);
13351337
// update nominator/denominator exponent
13361338
-- exponents[nom]; ++ exponents[denom];
13371339
// inner loop done
@@ -1352,8 +1354,10 @@ namespace Sass {
13521354
{
13531355
// opted to have these switches in the inner loop
13541356
// makes it more readable and should not cost much
1355-
if (exp.second < 0) denominator_units_.push_back(exp.first);
1356-
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1357+
if (!exp.first.empty()) {
1358+
if (exp.second < 0) denominator_units_.push_back(exp.first);
1359+
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1360+
}
13571361
}
13581362
}
13591363

@@ -1363,14 +1367,14 @@ namespace Sass {
13631367

13641368
// maybe convert to other unit
13651369
// easier implemented on its own
1366-
try { convert(prefered); }
1370+
try { convert(prefered, strict); }
13671371
catch (incompatibleUnits& err)
13681372
{ error(err.what(), pstate()); }
13691373
catch (...) { throw; }
13701374

13711375
}
13721376

1373-
void Number::convert(const string& prefered)
1377+
void Number::convert(const string& prefered, bool strict)
13741378
{
13751379
// abort if unit is empty
13761380
if (prefered.empty()) return;
@@ -1405,7 +1409,7 @@ namespace Sass {
14051409
if (string_to_unit(denom) == UNKNOWN) continue;
14061410
// we now have two convertable units
14071411
// add factor for current conversion
1408-
factor *= conversion_factor(denom, prefered);
1412+
factor *= conversion_factor(denom, prefered, strict);
14091413
// update nominator/denominator exponent
14101414
++ exponents[denom]; -- exponents[prefered];
14111415
}
@@ -1426,7 +1430,7 @@ namespace Sass {
14261430
if (string_to_unit(nom) == UNKNOWN) continue;
14271431
// we now have two convertable units
14281432
// add factor for current conversion
1429-
factor *= conversion_factor(nom, prefered);
1433+
factor *= conversion_factor(nom, prefered, strict);
14301434
// update nominator/denominator exponent
14311435
-- exponents[nom]; ++ exponents[prefered];
14321436
}
@@ -1444,8 +1448,10 @@ namespace Sass {
14441448
{
14451449
// opted to have these switches in the inner loop
14461450
// makes it more readable and should not cost much
1447-
if (exp.second < 0) denominator_units_.push_back(exp.first);
1448-
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1451+
if (!exp.first.empty()) {
1452+
if (exp.second < 0) denominator_units_.push_back(exp.first);
1453+
else if (exp.second > 0) numerator_units_.push_back(exp.first);
1454+
}
14491455
}
14501456
}
14511457

src/ast.hpp

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

12121212
bool is_unitless();
1213-
void convert(const string& unit = "");
1214-
void normalize(const string& unit = "");
1213+
void convert(const string& unit = "", bool strict = false);
1214+
void normalize(const string& unit = "", bool strict = false);
12151215
// useful for making one number compatible with another
12161216
string find_convertible_unit() const;
12171217

src/eval.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,8 @@ namespace Sass {
11201120
}
11211121

11221122
Number tmp(r);
1123-
tmp.normalize(l.find_convertible_unit());
1123+
bool strict = op != Sass_OP::MUL && op != Sass_OP::DIV;
1124+
tmp.normalize(l.find_convertible_unit(), strict);
11241125
string l_unit(l.unit());
11251126
string r_unit(tmp.unit());
11261127
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)