Skip to content

Commit ac49399

Browse files
committed
Merge remote-tracking branch 'origin/pr/1172'
2 parents 0a50d1c + 2653a4a commit ac49399

File tree

3 files changed

+222
-45
lines changed

3 files changed

+222
-45
lines changed

ast.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ namespace Sass {
663663
// skip already canceled out unit
664664
if (exponents[denom] >= 0) continue;
665665
// skip all units we don't know how to convert
666-
if (string_to_unit(denom) == INCOMMENSURABLE) continue;
666+
if (string_to_unit(denom) == UNKNOWN) continue;
667667
// now search for nominator
668668
while (nom_it != nom_end)
669669
{
@@ -672,7 +672,7 @@ namespace Sass {
672672
// skip already canceled out unit
673673
if (exponents[nom] <= 0) continue;
674674
// skip all units we don't know how to convert
675-
if (string_to_unit(nom) == INCOMMENSURABLE) continue;
675+
if (string_to_unit(nom) == UNKNOWN) continue;
676676
// we now have two convertable units
677677
// add factor for current conversion
678678
factor *= conversion_factor(nom, denom);
@@ -707,7 +707,10 @@ namespace Sass {
707707

708708
// maybe convert to other unit
709709
// easier implemented on its own
710-
convert(prefered);
710+
try { convert(prefered); }
711+
catch (incompatibleUnits& err)
712+
{ error(err.what(), pstate()); }
713+
catch (...) { throw; }
711714

712715
}
713716

@@ -743,7 +746,7 @@ namespace Sass {
743746
// skip already canceled out unit
744747
if (exponents[denom] >= 0) continue;
745748
// skip all units we don't know how to convert
746-
if (string_to_unit(denom) == INCOMMENSURABLE) continue;
749+
if (string_to_unit(denom) == UNKNOWN) continue;
747750
// we now have two convertable units
748751
// add factor for current conversion
749752
factor *= conversion_factor(denom, prefered);
@@ -764,7 +767,7 @@ namespace Sass {
764767
// skip already canceled out unit
765768
if (exponents[nom] <= 0) continue;
766769
// skip all units we don't know how to convert
767-
if (string_to_unit(nom) == INCOMMENSURABLE) continue;
770+
if (string_to_unit(nom) == UNKNOWN) continue;
768771
// we now have two convertable units
769772
// add factor for current conversion
770773
factor *= conversion_factor(nom, prefered);
@@ -801,11 +804,11 @@ namespace Sass {
801804
{
802805
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
803806
string u(numerator_units_[i]);
804-
if (string_to_unit(u) != INCOMMENSURABLE) return u;
807+
if (string_to_unit(u) != UNKNOWN) return u;
805808
}
806809
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
807810
string u(denominator_units_[i]);
808-
if (string_to_unit(u) != INCOMMENSURABLE) return u;
811+
if (string_to_unit(u) != UNKNOWN) return u;
809812
}
810813
return string();
811814
}

units.cpp

Lines changed: 134 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,155 @@
1+
#include <stdexcept>
12
#include "units.hpp"
23

3-
#define PI 3.14159265358979323846
4-
54
namespace Sass {
65

7-
double conversion_factors[10][10] = {
8-
/* in cm pc mm pt px deg grad rad turn */
9-
/* in */ { 1, 2.54, 6, 25.4, 72, 96, 1, 1, 1, 1 },
10-
/* cm */ { 1.0/2.54, 1, 6.0/2.54, 10, 72.0/2.54, 96.0/2.54, 1, 1, 1, 1 },
11-
/* pc */ { 1.0/6.0, 2.54/6.0, 1, 25.4/6.0, 72.0/6.0, 96.0/6.0, 1, 1, 1, 1 },
12-
/* mm */ { 1.0/25.4, 1.0/10.0, 6.0/25.4, 1, 72.0/25.4, 96.0/25.4, 1, 1, 1, 1 },
13-
/* pt */ { 1.0/72.0, 2.54/72.0, 6.0/72.0, 25.4/72.0, 1, 96.0/72.0, 1, 1, 1, 1 },
14-
/* px */ { 1.0/96.0, 2.54/96.0, 6.0/96.0, 25.4/96.0, 72.0/96.0, 1, 1, 1, 1, 1 },
15-
/* deg */ { 1 , 1 , 1 , 1 , 1 , 1, 1, 40.0/36.0, PI/180.0, 1.0/360.0 },
16-
/* grad */ { 1 , 1 , 1 , 1 , 1 , 1, 36.0/40.0, 1, PI/200.0, 1.0/400.0 },
17-
/* rad */ { 1 , 1 , 1 , 1 , 1 , 1, 180.0/PI, 200.0/PI, 1, PI/2.0 },
18-
/* turn */ { 1 , 1 , 1 , 1 , 1 , 1, 360.0/1.0, 400.0/1.0, 2.0*PI, 1 }
6+
/* the conversion matrix can be readed the following way */
7+
/* if you go down, the factor is for the numerator (multiply) */
8+
/* if you go right, the factor is for the denominator (divide) */
9+
/* and yes, we actually use both, not sure why, but why not!? */
10+
11+
const double size_conversion_factors[6][6] =
12+
{
13+
/* in cm pc mm pt px */
14+
/* in */ { 1, 2.54, 6, 25.4, 72, 96, },
15+
/* cm */ { 1.0/2.54, 1, 6.0/2.54, 10, 72.0/2.54, 96.0/2.54 },
16+
/* pc */ { 1.0/6.0, 2.54/6.0, 1, 25.4/6.0, 72.0/6.0, 96.0/6.0 },
17+
/* mm */ { 1.0/25.4, 1.0/10.0, 6.0/25.4, 1, 72.0/25.4, 96.0/25.4 },
18+
/* pt */ { 1.0/72.0, 2.54/72.0, 6.0/72.0, 25.4/72.0, 1, 96.0/72.0 },
19+
/* px */ { 1.0/96.0, 2.54/96.0, 6.0/96.0, 25.4/96.0, 72.0/96.0, 1, }
1920
};
2021

21-
Unit string_to_unit(const string& s)
22+
const double angle_conversion_factors[4][4] =
2223
{
23-
if (s == "in") return IN;
24-
else if (s == "cm") return CM;
24+
/* deg grad rad turn */
25+
/* deg */ { 1, 40.0/36.0, PI/180.0, 1.0/360.0 },
26+
/* grad */ { 36.0/40.0, 1, PI/200.0, 1.0/400.0 },
27+
/* rad */ { 180.0/PI, 200.0/PI, 1, 0.5/PI },
28+
/* turn */ { 360.0, 400.0, 2.0*PI, 1 }
29+
};
30+
31+
const double time_conversion_factors[2][2] =
32+
{
33+
/* s ms */
34+
/* s */ { 1, 1000.0 },
35+
/* ms */ { 1/1000.0, 1 }
36+
};
37+
const double frequency_conversion_factors[2][2] =
38+
{
39+
/* Hz kHz */
40+
/* Hz */ { 1, 1/1000.0 },
41+
/* kHz */ { 1000.0, 1 }
42+
};
43+
const double resolution_conversion_factors[3][3] =
44+
{
45+
/* dpi dpcm dppx */
46+
/* dpi */ { 1, 2.54, 96 },
47+
/* dpcm */ { 1/2.54, 1, 96/2.54 },
48+
/* dppx */ { 1/96.0, 2.54/96, 1 }
49+
};
50+
51+
SassUnitType get_unit_type(SassUnit unit)
52+
{
53+
switch (unit & 0xFF00)
54+
{
55+
case SIZE: return SIZE; break;
56+
case ANGLE: return ANGLE; break;
57+
case TIME: return TIME; break;
58+
case FREQUENCY: return FREQUENCY; break;
59+
case RESOLUTION: return RESOLUTION; break;
60+
default: return INCOMMENSURABLE; break;
61+
}
62+
};
63+
64+
SassUnit string_to_unit(const string& s)
65+
{
66+
// size units
67+
if (s == "px") return PX;
68+
else if (s == "pt") return PT;
2569
else if (s == "pc") return PC;
2670
else if (s == "mm") return MM;
27-
else if (s == "pt") return PT;
28-
else if (s == "px") return PX;
71+
else if (s == "cm") return CM;
72+
else if (s == "in") return IN;
73+
// angle units
2974
else if (s == "deg") return DEG;
3075
else if (s == "grad") return GRAD;
3176
else if (s == "rad") return RAD;
3277
else if (s == "turn") return TURN;
33-
else return INCOMMENSURABLE;
78+
// time units
79+
else if (s == "s") return SEC;
80+
else if (s == "ms") return MSEC;
81+
// frequency units
82+
else if (s == "Hz") return HERTZ;
83+
else if (s == "kHz") return KHERTZ;
84+
// resolutions units
85+
else if (s == "dpi") return DPI;
86+
else if (s == "dpcm") return DPCM;
87+
else if (s == "dppx") return DPPX;
88+
// for unknown units
89+
else return UNKNOWN;
3490
}
3591

36-
double conversion_factor(const string& s1, const string& s2)
92+
const char* unit_to_string(SassUnit unit)
3793
{
38-
Unit u1 = string_to_unit(s1);
39-
Unit u2 = string_to_unit(s2);
40-
double factor;
41-
if (u1 == INCOMMENSURABLE || u2 == INCOMMENSURABLE)
42-
factor = 0;
43-
else
44-
factor = conversion_factors[u1][u2];
45-
return factor;
94+
switch (unit) {
95+
// size units
96+
case PX: return "px"; break;
97+
case PT: return "pt"; break;
98+
case PC: return "pc"; break;
99+
case MM: return "mm"; break;
100+
case CM: return "cm"; break;
101+
case IN: return "in"; break;
102+
// angle units
103+
case DEG: return "deg"; break;
104+
case GRAD: return "grad"; break;
105+
case RAD: return "rad"; break;
106+
case TURN: return "turn"; break;
107+
// time units
108+
case SEC: return "s"; break;
109+
case MSEC: return "ms"; break;
110+
// frequency units
111+
case HERTZ: return "Hz"; break;
112+
case KHERTZ: return "kHz"; break;
113+
// resolutions units
114+
case DPI: return "dpi"; break;
115+
case DPCM: return "dpcm"; break;
116+
case DPPX: return "dppx"; break;
117+
// for unknown units
118+
default: return ""; break;;
119+
}
46120
}
47121

48-
/* not used anymore - remove?
49-
double convert(double n, const string& from, const string& to)
122+
// throws incompatibleUnits exceptions
123+
double conversion_factor(const string& s1, const string& s2)
50124
{
51-
double factor = conversion_factor(from, to);
52-
return factor ? factor * n : n;
53-
} */
125+
// assert for same units
126+
if (s1 == s2) return 1;
127+
// get unit enum from string
128+
SassUnit u1 = string_to_unit(s1);
129+
SassUnit u2 = string_to_unit(s2);
130+
// query unit group types
131+
SassUnitType t1 = get_unit_type(u1);
132+
SassUnitType t2 = get_unit_type(u2);
133+
// get absolute offset
134+
// used for array acces
135+
size_t i1 = u1 - t1;
136+
size_t i2 = u2 - t2;
137+
// error if units are not of the same group
138+
if (t1 != t2) throw incompatibleUnits(u1, u2);
139+
// only process known units
140+
if (u1 != UNKNOWN && u2 != UNKNOWN) {
141+
switch (t1) {
142+
case SIZE: return size_conversion_factors[i1][i2]; break;
143+
case ANGLE: return angle_conversion_factors[i1][i2]; break;
144+
case TIME: return time_conversion_factors[i1][i2]; break;
145+
case FREQUENCY: return frequency_conversion_factors[i1][i2]; break;
146+
case RESOLUTION: return resolution_conversion_factors[i1][i2]; break;
147+
// ToDo: should we throw error here?
148+
case INCOMMENSURABLE: return 0; break;
149+
}
150+
}
151+
// fallback
152+
return 1;
153+
}
54154

55155
}

units.hpp

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,89 @@
11
#ifndef SASS_UNITS_H
22
#define SASS_UNITS_H
33

4+
#include <cmath>
45
#include <string>
6+
#include <sstream>
57

68
namespace Sass {
79
using namespace std;
8-
enum Unit { IN, CM, PC, MM, PT, PX, DEG, GRAD, RAD, TURN, INCOMMENSURABLE };
9-
extern double conversion_factors[10][10];
10-
Unit string_to_unit(const string&);
10+
11+
const double PI = acos(-1);
12+
13+
enum SassUnitType {
14+
SIZE = 0x000,
15+
ANGLE = 0x100,
16+
TIME = 0x200,
17+
FREQUENCY = 0x300,
18+
RESOLUTION = 0x400,
19+
INCOMMENSURABLE = 0x500
20+
};
21+
22+
enum SassUnit {
23+
24+
// size units
25+
IN = SIZE,
26+
CM,
27+
PC,
28+
MM,
29+
PT,
30+
PX,
31+
32+
// angle units
33+
DEG = ANGLE,
34+
GRAD,
35+
RAD,
36+
TURN,
37+
38+
// time units
39+
SEC = TIME,
40+
MSEC,
41+
42+
// frequency units
43+
HERTZ = FREQUENCY,
44+
KHERTZ,
45+
46+
// resolutions units
47+
DPI = RESOLUTION,
48+
DPCM,
49+
DPPX,
50+
51+
// for unknown units
52+
UNKNOWN = INCOMMENSURABLE
53+
54+
};
55+
56+
extern const double size_conversion_factors[6][6];
57+
extern const double angle_conversion_factors[4][4];
58+
extern const double time_conversion_factors[2][2];
59+
extern const double frequency_conversion_factors[2][2];
60+
extern const double resolution_conversion_factors[3][3];
61+
62+
SassUnit string_to_unit(const string&);
63+
const char* unit_to_string(SassUnit unit);
64+
SassUnitType get_unit_type(SassUnit unit);
65+
// throws incompatibleUnits exceptions
1166
double conversion_factor(const string&, const string&);
12-
// double convert(double, const string&, const string&);
67+
68+
class incompatibleUnits: public exception
69+
{
70+
public:
71+
const char* msg;
72+
incompatibleUnits(SassUnit a, SassUnit b)
73+
: exception()
74+
{
75+
stringstream ss;
76+
ss << "Incompatible units: ";
77+
ss << "'" << unit_to_string(a) << "' and ";
78+
ss << "'" << unit_to_string(b) << "'";
79+
msg = ss.str().c_str();
80+
};
81+
virtual const char* what() const throw()
82+
{
83+
return msg;
84+
}
85+
};
86+
1387
}
1488

1589
#endif

0 commit comments

Comments
 (0)