sassc4 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +16 -0
  5. data/CHANGELOG.md +97 -0
  6. data/CODE_OF_CONDUCT.md +10 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +80 -0
  10. data/Rakefile +51 -0
  11. data/ext/depend +4 -0
  12. data/ext/extconf.rb +92 -0
  13. data/ext/libsass/VERSION +1 -0
  14. data/ext/libsass/contrib/plugin.cpp +60 -0
  15. data/ext/libsass/include/sass/base.h +97 -0
  16. data/ext/libsass/include/sass/context.h +174 -0
  17. data/ext/libsass/include/sass/functions.h +139 -0
  18. data/ext/libsass/include/sass/values.h +145 -0
  19. data/ext/libsass/include/sass/version.h +12 -0
  20. data/ext/libsass/include/sass.h +15 -0
  21. data/ext/libsass/include/sass2scss.h +120 -0
  22. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  23. data/ext/libsass/src/ast.cpp +953 -0
  24. data/ext/libsass/src/ast.hpp +1064 -0
  25. data/ext/libsass/src/ast2c.cpp +80 -0
  26. data/ext/libsass/src/ast2c.hpp +39 -0
  27. data/ext/libsass/src/ast_def_macros.hpp +140 -0
  28. data/ext/libsass/src/ast_fwd_decl.cpp +31 -0
  29. data/ext/libsass/src/ast_fwd_decl.hpp +274 -0
  30. data/ext/libsass/src/ast_helpers.hpp +316 -0
  31. data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
  32. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  33. data/ext/libsass/src/ast_sel_unify.cpp +275 -0
  34. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  35. data/ext/libsass/src/ast_selectors.cpp +1070 -0
  36. data/ext/libsass/src/ast_selectors.hpp +523 -0
  37. data/ext/libsass/src/ast_supports.cpp +114 -0
  38. data/ext/libsass/src/ast_supports.hpp +121 -0
  39. data/ext/libsass/src/ast_values.cpp +1154 -0
  40. data/ext/libsass/src/ast_values.hpp +498 -0
  41. data/ext/libsass/src/b64/cencode.h +32 -0
  42. data/ext/libsass/src/b64/encode.h +79 -0
  43. data/ext/libsass/src/backtrace.cpp +50 -0
  44. data/ext/libsass/src/backtrace.hpp +29 -0
  45. data/ext/libsass/src/base64vlq.cpp +47 -0
  46. data/ext/libsass/src/base64vlq.hpp +30 -0
  47. data/ext/libsass/src/bind.cpp +312 -0
  48. data/ext/libsass/src/bind.hpp +15 -0
  49. data/ext/libsass/src/c2ast.cpp +64 -0
  50. data/ext/libsass/src/c2ast.hpp +14 -0
  51. data/ext/libsass/src/c99func.c +54 -0
  52. data/ext/libsass/src/cencode.c +106 -0
  53. data/ext/libsass/src/check_nesting.cpp +393 -0
  54. data/ext/libsass/src/check_nesting.hpp +70 -0
  55. data/ext/libsass/src/color_maps.cpp +652 -0
  56. data/ext/libsass/src/color_maps.hpp +323 -0
  57. data/ext/libsass/src/color_spaces.cpp +241 -0
  58. data/ext/libsass/src/color_spaces.hpp +227 -0
  59. data/ext/libsass/src/constants.cpp +199 -0
  60. data/ext/libsass/src/constants.hpp +200 -0
  61. data/ext/libsass/src/context.cpp +870 -0
  62. data/ext/libsass/src/context.hpp +140 -0
  63. data/ext/libsass/src/cssize.cpp +521 -0
  64. data/ext/libsass/src/cssize.hpp +71 -0
  65. data/ext/libsass/src/dart_helpers.hpp +199 -0
  66. data/ext/libsass/src/debug.hpp +43 -0
  67. data/ext/libsass/src/debugger.hpp +964 -0
  68. data/ext/libsass/src/emitter.cpp +297 -0
  69. data/ext/libsass/src/emitter.hpp +101 -0
  70. data/ext/libsass/src/environment.cpp +260 -0
  71. data/ext/libsass/src/environment.hpp +124 -0
  72. data/ext/libsass/src/error_handling.cpp +239 -0
  73. data/ext/libsass/src/error_handling.hpp +248 -0
  74. data/ext/libsass/src/eval.cpp +1543 -0
  75. data/ext/libsass/src/eval.hpp +110 -0
  76. data/ext/libsass/src/eval_selectors.cpp +75 -0
  77. data/ext/libsass/src/expand.cpp +875 -0
  78. data/ext/libsass/src/expand.hpp +98 -0
  79. data/ext/libsass/src/extender.cpp +1226 -0
  80. data/ext/libsass/src/extender.hpp +399 -0
  81. data/ext/libsass/src/extension.cpp +43 -0
  82. data/ext/libsass/src/extension.hpp +89 -0
  83. data/ext/libsass/src/file.cpp +531 -0
  84. data/ext/libsass/src/file.hpp +124 -0
  85. data/ext/libsass/src/fn_colors.cpp +836 -0
  86. data/ext/libsass/src/fn_colors.hpp +99 -0
  87. data/ext/libsass/src/fn_lists.cpp +285 -0
  88. data/ext/libsass/src/fn_lists.hpp +34 -0
  89. data/ext/libsass/src/fn_maps.cpp +94 -0
  90. data/ext/libsass/src/fn_maps.hpp +30 -0
  91. data/ext/libsass/src/fn_miscs.cpp +248 -0
  92. data/ext/libsass/src/fn_miscs.hpp +40 -0
  93. data/ext/libsass/src/fn_numbers.cpp +246 -0
  94. data/ext/libsass/src/fn_numbers.hpp +45 -0
  95. data/ext/libsass/src/fn_selectors.cpp +205 -0
  96. data/ext/libsass/src/fn_selectors.hpp +35 -0
  97. data/ext/libsass/src/fn_strings.cpp +268 -0
  98. data/ext/libsass/src/fn_strings.hpp +34 -0
  99. data/ext/libsass/src/fn_utils.cpp +159 -0
  100. data/ext/libsass/src/fn_utils.hpp +62 -0
  101. data/ext/libsass/src/inspect.cpp +1126 -0
  102. data/ext/libsass/src/inspect.hpp +101 -0
  103. data/ext/libsass/src/json.cpp +1436 -0
  104. data/ext/libsass/src/json.hpp +117 -0
  105. data/ext/libsass/src/kwd_arg_macros.hpp +28 -0
  106. data/ext/libsass/src/lexer.cpp +122 -0
  107. data/ext/libsass/src/lexer.hpp +304 -0
  108. data/ext/libsass/src/listize.cpp +70 -0
  109. data/ext/libsass/src/listize.hpp +37 -0
  110. data/ext/libsass/src/mapping.hpp +19 -0
  111. data/ext/libsass/src/memory/allocator.cpp +48 -0
  112. data/ext/libsass/src/memory/allocator.hpp +138 -0
  113. data/ext/libsass/src/memory/config.hpp +20 -0
  114. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  115. data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
  116. data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
  117. data/ext/libsass/src/memory.hpp +12 -0
  118. data/ext/libsass/src/operation.hpp +223 -0
  119. data/ext/libsass/src/operators.cpp +267 -0
  120. data/ext/libsass/src/operators.hpp +30 -0
  121. data/ext/libsass/src/ordered_map.hpp +112 -0
  122. data/ext/libsass/src/output.cpp +320 -0
  123. data/ext/libsass/src/output.hpp +47 -0
  124. data/ext/libsass/src/parser.cpp +3059 -0
  125. data/ext/libsass/src/parser.hpp +395 -0
  126. data/ext/libsass/src/parser_selectors.cpp +189 -0
  127. data/ext/libsass/src/permutate.hpp +164 -0
  128. data/ext/libsass/src/plugins.cpp +188 -0
  129. data/ext/libsass/src/plugins.hpp +57 -0
  130. data/ext/libsass/src/position.cpp +163 -0
  131. data/ext/libsass/src/position.hpp +147 -0
  132. data/ext/libsass/src/prelexer.cpp +1780 -0
  133. data/ext/libsass/src/prelexer.hpp +484 -0
  134. data/ext/libsass/src/remove_placeholders.cpp +86 -0
  135. data/ext/libsass/src/remove_placeholders.hpp +37 -0
  136. data/ext/libsass/src/sass.cpp +156 -0
  137. data/ext/libsass/src/sass.hpp +147 -0
  138. data/ext/libsass/src/sass2scss.cpp +895 -0
  139. data/ext/libsass/src/sass_context.cpp +742 -0
  140. data/ext/libsass/src/sass_context.hpp +129 -0
  141. data/ext/libsass/src/sass_functions.cpp +210 -0
  142. data/ext/libsass/src/sass_functions.hpp +50 -0
  143. data/ext/libsass/src/sass_values.cpp +362 -0
  144. data/ext/libsass/src/sass_values.hpp +82 -0
  145. data/ext/libsass/src/settings.hpp +19 -0
  146. data/ext/libsass/src/source.cpp +69 -0
  147. data/ext/libsass/src/source.hpp +95 -0
  148. data/ext/libsass/src/source_data.hpp +32 -0
  149. data/ext/libsass/src/source_map.cpp +202 -0
  150. data/ext/libsass/src/source_map.hpp +65 -0
  151. data/ext/libsass/src/stylesheet.cpp +22 -0
  152. data/ext/libsass/src/stylesheet.hpp +57 -0
  153. data/ext/libsass/src/to_value.cpp +114 -0
  154. data/ext/libsass/src/to_value.hpp +46 -0
  155. data/ext/libsass/src/units.cpp +507 -0
  156. data/ext/libsass/src/units.hpp +110 -0
  157. data/ext/libsass/src/utf8/checked.h +336 -0
  158. data/ext/libsass/src/utf8/core.h +332 -0
  159. data/ext/libsass/src/utf8/unchecked.h +235 -0
  160. data/ext/libsass/src/utf8.h +34 -0
  161. data/ext/libsass/src/utf8_string.cpp +104 -0
  162. data/ext/libsass/src/utf8_string.hpp +38 -0
  163. data/ext/libsass/src/util.cpp +723 -0
  164. data/ext/libsass/src/util.hpp +105 -0
  165. data/ext/libsass/src/util_string.cpp +125 -0
  166. data/ext/libsass/src/util_string.hpp +73 -0
  167. data/ext/libsass/src/values.cpp +140 -0
  168. data/ext/libsass/src/values.hpp +12 -0
  169. data/lib/sassc/dependency.rb +17 -0
  170. data/lib/sassc/engine.rb +141 -0
  171. data/lib/sassc/error.rb +37 -0
  172. data/lib/sassc/functions_handler.rb +73 -0
  173. data/lib/sassc/import_handler.rb +50 -0
  174. data/lib/sassc/importer.rb +31 -0
  175. data/lib/sassc/native/native_context_api.rb +147 -0
  176. data/lib/sassc/native/native_functions_api.rb +159 -0
  177. data/lib/sassc/native/sass2scss_api.rb +10 -0
  178. data/lib/sassc/native/sass_input_style.rb +13 -0
  179. data/lib/sassc/native/sass_output_style.rb +12 -0
  180. data/lib/sassc/native/sass_value.rb +97 -0
  181. data/lib/sassc/native/string_list.rb +10 -0
  182. data/lib/sassc/native.rb +64 -0
  183. data/lib/sassc/sass_2_scss.rb +9 -0
  184. data/lib/sassc/script/functions.rb +8 -0
  185. data/lib/sassc/script/value/bool.rb +32 -0
  186. data/lib/sassc/script/value/color.rb +95 -0
  187. data/lib/sassc/script/value/list.rb +136 -0
  188. data/lib/sassc/script/value/map.rb +69 -0
  189. data/lib/sassc/script/value/number.rb +389 -0
  190. data/lib/sassc/script/value/string.rb +96 -0
  191. data/lib/sassc/script/value.rb +137 -0
  192. data/lib/sassc/script/value_conversion/base.rb +13 -0
  193. data/lib/sassc/script/value_conversion/bool.rb +13 -0
  194. data/lib/sassc/script/value_conversion/color.rb +18 -0
  195. data/lib/sassc/script/value_conversion/list.rb +25 -0
  196. data/lib/sassc/script/value_conversion/map.rb +21 -0
  197. data/lib/sassc/script/value_conversion/number.rb +13 -0
  198. data/lib/sassc/script/value_conversion/string.rb +17 -0
  199. data/lib/sassc/script/value_conversion.rb +69 -0
  200. data/lib/sassc/script.rb +17 -0
  201. data/lib/sassc/util/normalized_map.rb +117 -0
  202. data/lib/sassc/util.rb +231 -0
  203. data/lib/sassc/version.rb +5 -0
  204. data/lib/sassc.rb +57 -0
  205. data/sassc.gemspec +69 -0
  206. data/test/css_color_level4_test.rb +168 -0
  207. data/test/custom_importer_test.rb +127 -0
  208. data/test/engine_test.rb +314 -0
  209. data/test/error_test.rb +29 -0
  210. data/test/fixtures/paths.scss +10 -0
  211. data/test/functions_test.rb +340 -0
  212. data/test/native_test.rb +213 -0
  213. data/test/output_style_test.rb +107 -0
  214. data/test/sass_2_scss_test.rb +14 -0
  215. data/test/test_helper.rb +45 -0
  216. metadata +396 -0
@@ -0,0 +1,507 @@
1
+ #include "sass.hpp"
2
+ #include <map>
3
+ #include <stdexcept>
4
+ #include <algorithm>
5
+ #include "units.hpp"
6
+ #include "error_handling.hpp"
7
+
8
+ namespace Sass {
9
+
10
+ /* the conversion matrix can be readed the following way */
11
+ /* if you go down, the factor is for the numerator (multiply) */
12
+ /* if you go right, the factor is for the denominator (divide) */
13
+ /* and yes, we actually use both, not sure why, but why not!? */
14
+
15
+ const double size_conversion_factors[6][6] =
16
+ {
17
+ /* in cm pc mm pt px */
18
+ /* in */ { 1, 2.54, 6, 25.4, 72, 96, },
19
+ /* cm */ { 1.0/2.54, 1, 6.0/2.54, 10, 72.0/2.54, 96.0/2.54 },
20
+ /* pc */ { 1.0/6.0, 2.54/6.0, 1, 25.4/6.0, 72.0/6.0, 96.0/6.0 },
21
+ /* mm */ { 1.0/25.4, 1.0/10.0, 6.0/25.4, 1, 72.0/25.4, 96.0/25.4 },
22
+ /* pt */ { 1.0/72.0, 2.54/72.0, 6.0/72.0, 25.4/72.0, 1, 96.0/72.0 },
23
+ /* px */ { 1.0/96.0, 2.54/96.0, 6.0/96.0, 25.4/96.0, 72.0/96.0, 1, }
24
+ };
25
+
26
+ const double angle_conversion_factors[4][4] =
27
+ {
28
+ /* deg grad rad turn */
29
+ /* deg */ { 1, 40.0/36.0, PI/180.0, 1.0/360.0 },
30
+ /* grad */ { 36.0/40.0, 1, PI/200.0, 1.0/400.0 },
31
+ /* rad */ { 180.0/PI, 200.0/PI, 1, 0.5/PI },
32
+ /* turn */ { 360.0, 400.0, 2.0*PI, 1 }
33
+ };
34
+
35
+ const double time_conversion_factors[2][2] =
36
+ {
37
+ /* s ms */
38
+ /* s */ { 1, 1000.0 },
39
+ /* ms */ { 1/1000.0, 1 }
40
+ };
41
+ const double frequency_conversion_factors[2][2] =
42
+ {
43
+ /* Hz kHz */
44
+ /* Hz */ { 1, 1/1000.0 },
45
+ /* kHz */ { 1000.0, 1 }
46
+ };
47
+ const double resolution_conversion_factors[3][3] =
48
+ {
49
+ /* dpi dpcm dppx */
50
+ /* dpi */ { 1, 1/2.54, 1/96.0 },
51
+ /* dpcm */ { 2.54, 1, 2.54/96 },
52
+ /* dppx */ { 96, 96/2.54, 1 }
53
+ };
54
+
55
+ UnitClass get_unit_type(UnitType unit)
56
+ {
57
+ switch (unit & 0xFF00)
58
+ {
59
+ case UnitClass::LENGTH: return UnitClass::LENGTH;
60
+ case UnitClass::ANGLE: return UnitClass::ANGLE;
61
+ case UnitClass::TIME: return UnitClass::TIME;
62
+ case UnitClass::FREQUENCY: return UnitClass::FREQUENCY;
63
+ case UnitClass::RESOLUTION: return UnitClass::RESOLUTION;
64
+ default: return UnitClass::INCOMMENSURABLE;
65
+ }
66
+ };
67
+
68
+ sass::string get_unit_class(UnitType unit)
69
+ {
70
+ switch (unit & 0xFF00)
71
+ {
72
+ case UnitClass::LENGTH: return "LENGTH";
73
+ case UnitClass::ANGLE: return "ANGLE";
74
+ case UnitClass::TIME: return "TIME";
75
+ case UnitClass::FREQUENCY: return "FREQUENCY";
76
+ case UnitClass::RESOLUTION: return "RESOLUTION";
77
+ default: return "INCOMMENSURABLE";
78
+ }
79
+ };
80
+
81
+ UnitType get_main_unit(const UnitClass unit)
82
+ {
83
+ switch (unit)
84
+ {
85
+ case UnitClass::LENGTH: return UnitType::PX;
86
+ case UnitClass::ANGLE: return UnitType::DEG;
87
+ case UnitClass::TIME: return UnitType::SEC;
88
+ case UnitClass::FREQUENCY: return UnitType::HERTZ;
89
+ case UnitClass::RESOLUTION: return UnitType::DPI;
90
+ default: return UnitType::UNKNOWN;
91
+ }
92
+ };
93
+
94
+ UnitType string_to_unit(const sass::string& s)
95
+ {
96
+ // size units
97
+ if (s == "px") return UnitType::PX;
98
+ else if (s == "pt") return UnitType::PT;
99
+ else if (s == "pc") return UnitType::PC;
100
+ else if (s == "mm") return UnitType::MM;
101
+ else if (s == "cm") return UnitType::CM;
102
+ else if (s == "in") return UnitType::IN;
103
+ // angle units
104
+ else if (s == "deg") return UnitType::DEG;
105
+ else if (s == "grad") return UnitType::GRAD;
106
+ else if (s == "rad") return UnitType::RAD;
107
+ else if (s == "turn") return UnitType::TURN;
108
+ // time units
109
+ else if (s == "s") return UnitType::SEC;
110
+ else if (s == "ms") return UnitType::MSEC;
111
+ // frequency units
112
+ else if (s == "Hz") return UnitType::HERTZ;
113
+ else if (s == "kHz") return UnitType::KHERTZ;
114
+ // resolutions units
115
+ else if (s == "dpi") return UnitType::DPI;
116
+ else if (s == "dpcm") return UnitType::DPCM;
117
+ else if (s == "dppx") return UnitType::DPPX;
118
+ // for unknown units
119
+ else return UnitType::UNKNOWN;
120
+ }
121
+
122
+ const char* unit_to_string(UnitType unit)
123
+ {
124
+ switch (unit) {
125
+ // size units
126
+ case UnitType::PX: return "px";
127
+ case UnitType::PT: return "pt";
128
+ case UnitType::PC: return "pc";
129
+ case UnitType::MM: return "mm";
130
+ case UnitType::CM: return "cm";
131
+ case UnitType::IN: return "in";
132
+ // angle units
133
+ case UnitType::DEG: return "deg";
134
+ case UnitType::GRAD: return "grad";
135
+ case UnitType::RAD: return "rad";
136
+ case UnitType::TURN: return "turn";
137
+ // time units
138
+ case UnitType::SEC: return "s";
139
+ case UnitType::MSEC: return "ms";
140
+ // frequency units
141
+ case UnitType::HERTZ: return "Hz";
142
+ case UnitType::KHERTZ: return "kHz";
143
+ // resolutions units
144
+ case UnitType::DPI: return "dpi";
145
+ case UnitType::DPCM: return "dpcm";
146
+ case UnitType::DPPX: return "dppx";
147
+ // for unknown units
148
+ default: return "";
149
+ }
150
+ }
151
+
152
+ sass::string unit_to_class(const sass::string& s)
153
+ {
154
+ if (s == "px") return "LENGTH";
155
+ else if (s == "pt") return "LENGTH";
156
+ else if (s == "pc") return "LENGTH";
157
+ else if (s == "mm") return "LENGTH";
158
+ else if (s == "cm") return "LENGTH";
159
+ else if (s == "in") return "LENGTH";
160
+ // angle units
161
+ else if (s == "deg") return "ANGLE";
162
+ else if (s == "grad") return "ANGLE";
163
+ else if (s == "rad") return "ANGLE";
164
+ else if (s == "turn") return "ANGLE";
165
+ // time units
166
+ else if (s == "s") return "TIME";
167
+ else if (s == "ms") return "TIME";
168
+ // frequency units
169
+ else if (s == "Hz") return "FREQUENCY";
170
+ else if (s == "kHz") return "FREQUENCY";
171
+ // resolutions units
172
+ else if (s == "dpi") return "RESOLUTION";
173
+ else if (s == "dpcm") return "RESOLUTION";
174
+ else if (s == "dppx") return "RESOLUTION";
175
+ // for unknown units
176
+ return "CUSTOM:" + s;
177
+ }
178
+
179
+ // throws incompatibleUnits exceptions
180
+ double conversion_factor(const sass::string& s1, const sass::string& s2)
181
+ {
182
+ // assert for same units
183
+ if (s1 == s2) return 1;
184
+ // get unit enum from string
185
+ UnitType u1 = string_to_unit(s1);
186
+ UnitType u2 = string_to_unit(s2);
187
+ // query unit group types
188
+ UnitClass t1 = get_unit_type(u1);
189
+ UnitClass t2 = get_unit_type(u2);
190
+ // return the conversion factor
191
+ return conversion_factor(u1, u2, t1, t2);
192
+ }
193
+
194
+ // throws incompatibleUnits exceptions
195
+ double conversion_factor(UnitType u1, UnitType u2, UnitClass t1, UnitClass t2)
196
+ {
197
+ // can't convert between groups
198
+ if (t1 != t2) return 0;
199
+ // get absolute offset
200
+ // used for array acces
201
+ size_t i1 = u1 - t1;
202
+ size_t i2 = u2 - t2;
203
+ // process known units
204
+ switch (t1) {
205
+ case LENGTH:
206
+ return size_conversion_factors[i1][i2];
207
+ case ANGLE:
208
+ return angle_conversion_factors[i1][i2];
209
+ case TIME:
210
+ return time_conversion_factors[i1][i2];
211
+ case FREQUENCY:
212
+ return frequency_conversion_factors[i1][i2];
213
+ case RESOLUTION:
214
+ return resolution_conversion_factors[i1][i2];
215
+ case INCOMMENSURABLE:
216
+ return 0;
217
+ }
218
+ // fallback
219
+ return 0;
220
+ }
221
+
222
+ double convert_units(const sass::string& lhs, const sass::string& rhs, int& lhsexp, int& rhsexp)
223
+ {
224
+ double f = 0;
225
+ // do not convert same ones
226
+ if (lhs == rhs) return 0;
227
+ // skip already canceled out unit
228
+ if (lhsexp == 0) return 0;
229
+ if (rhsexp == 0) return 0;
230
+ // check if it can be converted
231
+ UnitType ulhs = string_to_unit(lhs);
232
+ UnitType urhs = string_to_unit(rhs);
233
+ // skip units we cannot convert
234
+ if (ulhs == UNKNOWN) return 0;
235
+ if (urhs == UNKNOWN) return 0;
236
+ // query unit group types
237
+ UnitClass clhs = get_unit_type(ulhs);
238
+ UnitClass crhs = get_unit_type(urhs);
239
+ // skip units we cannot convert
240
+ if (clhs != crhs) return 0;
241
+ // if right denominator is bigger than lhs, we want to keep it in rhs unit
242
+ if (rhsexp < 0 && lhsexp > 0 && - rhsexp > lhsexp) {
243
+ // get the conversion factor for units
244
+ f = conversion_factor(urhs, ulhs, clhs, crhs);
245
+ // left hand side has been consumned
246
+ f = std::pow(f, lhsexp);
247
+ rhsexp += lhsexp;
248
+ lhsexp = 0;
249
+ }
250
+ else {
251
+ // get the conversion factor for units
252
+ f = conversion_factor(ulhs, urhs, clhs, crhs);
253
+ // right hand side has been consumned
254
+ f = std::pow(f, rhsexp);
255
+ lhsexp += rhsexp;
256
+ rhsexp = 0;
257
+ }
258
+ return f;
259
+ }
260
+
261
+ bool Units::operator< (const Units& rhs) const
262
+ {
263
+ return (numerators < rhs.numerators) &&
264
+ (denominators < rhs.denominators);
265
+ }
266
+ bool Units::operator== (const Units& rhs) const
267
+ {
268
+ return (numerators == rhs.numerators) &&
269
+ (denominators == rhs.denominators);
270
+ }
271
+ bool Units::operator!= (const Units& rhs) const
272
+ {
273
+ return ! (*this == rhs);
274
+ }
275
+
276
+ double Units::normalize()
277
+ {
278
+
279
+ size_t iL = numerators.size();
280
+ size_t nL = denominators.size();
281
+
282
+ // the final conversion factor
283
+ double factor = 1;
284
+
285
+ for (size_t i = 0; i < iL; i++) {
286
+ sass::string &lhs = numerators[i];
287
+ UnitType ulhs = string_to_unit(lhs);
288
+ if (ulhs == UNKNOWN) continue;
289
+ UnitClass clhs = get_unit_type(ulhs);
290
+ UnitType umain = get_main_unit(clhs);
291
+ if (ulhs == umain) continue;
292
+ double f(conversion_factor(umain, ulhs, clhs, clhs));
293
+ if (f == 0) throw std::runtime_error("INVALID");
294
+ numerators[i] = unit_to_string(umain);
295
+ factor /= f;
296
+ }
297
+
298
+ for (size_t n = 0; n < nL; n++) {
299
+ sass::string &rhs = denominators[n];
300
+ UnitType urhs = string_to_unit(rhs);
301
+ if (urhs == UNKNOWN) continue;
302
+ UnitClass crhs = get_unit_type(urhs);
303
+ UnitType umain = get_main_unit(crhs);
304
+ if (urhs == umain) continue;
305
+ double f(conversion_factor(umain, urhs, crhs, crhs));
306
+ if (f == 0) throw std::runtime_error("INVALID");
307
+ denominators[n] = unit_to_string(umain);
308
+ factor /= f;
309
+ }
310
+
311
+ std::sort (numerators.begin(), numerators.end());
312
+ std::sort (denominators.begin(), denominators.end());
313
+
314
+ // return for conversion
315
+ return factor;
316
+ }
317
+
318
+ double Units::reduce()
319
+ {
320
+
321
+ size_t iL = numerators.size();
322
+ size_t nL = denominators.size();
323
+
324
+ // have less than two units?
325
+ if (iL + nL < 2) return 1;
326
+
327
+ // first make sure same units cancel each other out
328
+ // it seems that a map table will fit nicely to do this
329
+ // we basically construct exponents for each unit
330
+ // has the advantage that they will be pre-sorted
331
+ std::map<sass::string, int> exponents;
332
+
333
+ // initialize by summing up occurrences in unit vectors
334
+ // this will already cancel out equivalent units (e.q. px/px)
335
+ for (size_t i = 0; i < iL; i ++) exponents[numerators[i]] += 1;
336
+ for (size_t n = 0; n < nL; n ++) exponents[denominators[n]] -= 1;
337
+
338
+ // the final conversion factor
339
+ double factor = 1;
340
+
341
+ // convert between compatible units
342
+ for (size_t i = 0; i < iL; i++) {
343
+ for (size_t n = 0; n < nL; n++) {
344
+ sass::string &lhs = numerators[i], &rhs = denominators[n];
345
+ int &lhsexp = exponents[lhs], &rhsexp = exponents[rhs];
346
+ double f(convert_units(lhs, rhs, lhsexp, rhsexp));
347
+ if (f == 0) continue;
348
+ factor /= f;
349
+ }
350
+ }
351
+
352
+ // now we can build up the new unit arrays
353
+ numerators.clear();
354
+ denominators.clear();
355
+
356
+ // recreate sorted units vectors
357
+ for (auto exp : exponents) {
358
+ int &exponent = exp.second;
359
+ while (exponent > 0 && exponent --)
360
+ numerators.push_back(exp.first);
361
+ while (exponent < 0 && exponent ++)
362
+ denominators.push_back(exp.first);
363
+ }
364
+
365
+ // return for conversion
366
+ return factor;
367
+
368
+ }
369
+
370
+ sass::string Units::unit() const
371
+ {
372
+ sass::string u;
373
+ size_t iL = numerators.size();
374
+ size_t nL = denominators.size();
375
+ for (size_t i = 0; i < iL; i += 1) {
376
+ if (i) u += '*';
377
+ u += numerators[i];
378
+ }
379
+ if (nL != 0) u += '/';
380
+ for (size_t n = 0; n < nL; n += 1) {
381
+ if (n) u += '*';
382
+ u += denominators[n];
383
+ }
384
+ return u;
385
+ }
386
+
387
+ bool Units::is_unitless() const
388
+ {
389
+ return numerators.empty() &&
390
+ denominators.empty();
391
+ }
392
+
393
+ bool Units::is_valid_css_unit() const
394
+ {
395
+ return numerators.size() <= 1 &&
396
+ denominators.size() == 0;
397
+ }
398
+
399
+ // this does not cover all cases (multiple preferred units)
400
+ double Units::convert_factor(const Units& r) const
401
+ {
402
+
403
+ sass::vector<sass::string> miss_nums(0);
404
+ sass::vector<sass::string> miss_dens(0);
405
+ // create copy since we need these for state keeping
406
+ sass::vector<sass::string> r_nums(r.numerators);
407
+ sass::vector<sass::string> r_dens(r.denominators);
408
+
409
+ auto l_num_it = numerators.begin();
410
+ auto l_num_end = numerators.end();
411
+
412
+ bool l_unitless = is_unitless();
413
+ auto r_unitless = r.is_unitless();
414
+
415
+ // overall conversion
416
+ double factor = 1;
417
+
418
+ // process all left numerators
419
+ while (l_num_it != l_num_end)
420
+ {
421
+ // get and increment afterwards
422
+ const sass::string l_num = *(l_num_it ++);
423
+
424
+ auto r_num_it = r_nums.begin(), r_num_end = r_nums.end();
425
+
426
+ bool found = false;
427
+ // search for compatible numerator
428
+ while (r_num_it != r_num_end)
429
+ {
430
+ // get and increment afterwards
431
+ const sass::string r_num = *(r_num_it);
432
+ // get possible conversion factor for units
433
+ double conversion = conversion_factor(l_num, r_num);
434
+ // skip incompatible numerator
435
+ if (conversion == 0) {
436
+ ++ r_num_it;
437
+ continue;
438
+ }
439
+ // apply to global factor
440
+ factor *= conversion;
441
+ // remove item from vector
442
+ r_nums.erase(r_num_it);
443
+ // found numerator
444
+ found = true;
445
+ break;
446
+ }
447
+ // maybe we did not find any
448
+ // left numerator is leftover
449
+ if (!found) miss_nums.push_back(l_num);
450
+ }
451
+
452
+ auto l_den_it = denominators.begin();
453
+ auto l_den_end = denominators.end();
454
+
455
+ // process all left denominators
456
+ while (l_den_it != l_den_end)
457
+ {
458
+ // get and increment afterwards
459
+ const sass::string l_den = *(l_den_it ++);
460
+
461
+ auto r_den_it = r_dens.begin();
462
+ auto r_den_end = r_dens.end();
463
+
464
+ bool found = false;
465
+ // search for compatible denominator
466
+ while (r_den_it != r_den_end)
467
+ {
468
+ // get and increment afterwards
469
+ const sass::string r_den = *(r_den_it);
470
+ // get possible conversion factor for units
471
+ double conversion = conversion_factor(l_den, r_den);
472
+ // skip incompatible denominator
473
+ if (conversion == 0) {
474
+ ++ r_den_it;
475
+ continue;
476
+ }
477
+ // apply to global factor
478
+ factor /= conversion;
479
+ // remove item from vector
480
+ r_dens.erase(r_den_it);
481
+ // found denominator
482
+ found = true;
483
+ break;
484
+ }
485
+ // maybe we did not find any
486
+ // left denominator is leftover
487
+ if (!found) miss_dens.push_back(l_den);
488
+ }
489
+
490
+ // check left-overs (ToDo: might cancel out?)
491
+ if (miss_nums.size() > 0 && !r_unitless) {
492
+ throw Exception::IncompatibleUnits(r, *this);
493
+ }
494
+ else if (miss_dens.size() > 0 && !r_unitless) {
495
+ throw Exception::IncompatibleUnits(r, *this);
496
+ }
497
+ else if (r_nums.size() > 0 && !l_unitless) {
498
+ throw Exception::IncompatibleUnits(r, *this);
499
+ }
500
+ else if (r_dens.size() > 0 && !l_unitless) {
501
+ throw Exception::IncompatibleUnits(r, *this);
502
+ }
503
+
504
+ return factor;
505
+ }
506
+
507
+ }
@@ -0,0 +1,110 @@
1
+ #ifndef SASS_UNITS_H
2
+ #define SASS_UNITS_H
3
+
4
+ #include <cmath>
5
+ #include <string>
6
+ #include <sstream>
7
+ #include <vector>
8
+
9
+ namespace Sass {
10
+
11
+ const double PI = std::acos(-1);
12
+
13
+ enum UnitClass {
14
+ LENGTH = 0x000,
15
+ ANGLE = 0x100,
16
+ TIME = 0x200,
17
+ FREQUENCY = 0x300,
18
+ RESOLUTION = 0x400,
19
+ INCOMMENSURABLE = 0x500
20
+ };
21
+
22
+ enum UnitType {
23
+
24
+ // size units
25
+ IN = UnitClass::LENGTH,
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
+ class Units {
57
+ public:
58
+ sass::vector<sass::string> numerators;
59
+ sass::vector<sass::string> denominators;
60
+ public:
61
+ // default constructor
62
+ Units() :
63
+ numerators(),
64
+ denominators()
65
+ { }
66
+ // copy constructor
67
+ Units(const Units* ptr) :
68
+ numerators(ptr->numerators),
69
+ denominators(ptr->denominators)
70
+ { }
71
+ // convert to string
72
+ sass::string unit() const;
73
+ // get if units are empty
74
+ bool is_unitless() const;
75
+ // return if valid for css
76
+ bool is_valid_css_unit() const;
77
+ // reduce units for output
78
+ // returns conversion factor
79
+ double reduce();
80
+ // normalize units for compare
81
+ // returns conversion factor
82
+ double normalize();
83
+ // compare operations
84
+ bool operator< (const Units& rhs) const;
85
+ bool operator== (const Units& rhs) const;
86
+ bool operator!= (const Units& rhs) const;
87
+ // factor to convert into given units
88
+ double convert_factor(const Units&) const;
89
+ };
90
+
91
+ extern const double size_conversion_factors[6][6];
92
+ extern const double angle_conversion_factors[4][4];
93
+ extern const double time_conversion_factors[2][2];
94
+ extern const double frequency_conversion_factors[2][2];
95
+ extern const double resolution_conversion_factors[3][3];
96
+
97
+ UnitType get_main_unit(const UnitClass unit);
98
+ enum Sass::UnitType string_to_unit(const sass::string&);
99
+ const char* unit_to_string(Sass::UnitType unit);
100
+ enum Sass::UnitClass get_unit_type(Sass::UnitType unit);
101
+ sass::string get_unit_class(Sass::UnitType unit);
102
+ sass::string unit_to_class(const sass::string&);
103
+ // throws incompatibleUnits exceptions
104
+ double conversion_factor(const sass::string&, const sass::string&);
105
+ double conversion_factor(UnitType, UnitType, UnitClass, UnitClass);
106
+ double convert_units(const sass::string&, const sass::string&, int&, int&);
107
+
108
+ }
109
+
110
+ #endif