cataract 0.1.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 (90) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-tidy +30 -0
  3. data/.github/workflows/ci-macos.yml +12 -0
  4. data/.github/workflows/ci.yml +77 -0
  5. data/.github/workflows/test.yml +76 -0
  6. data/.gitignore +45 -0
  7. data/.overcommit.yml +38 -0
  8. data/.rubocop.yml +83 -0
  9. data/BENCHMARKS.md +201 -0
  10. data/CHANGELOG.md +1 -0
  11. data/Gemfile +27 -0
  12. data/LICENSE +21 -0
  13. data/RAGEL_MIGRATION.md +60 -0
  14. data/README.md +292 -0
  15. data/Rakefile +209 -0
  16. data/benchmarks/benchmark_harness.rb +193 -0
  17. data/benchmarks/benchmark_merging.rb +121 -0
  18. data/benchmarks/benchmark_optimization_comparison.rb +168 -0
  19. data/benchmarks/benchmark_parsing.rb +153 -0
  20. data/benchmarks/benchmark_ragel_removal.rb +56 -0
  21. data/benchmarks/benchmark_runner.rb +70 -0
  22. data/benchmarks/benchmark_serialization.rb +180 -0
  23. data/benchmarks/benchmark_shorthand.rb +109 -0
  24. data/benchmarks/benchmark_shorthand_expansion.rb +176 -0
  25. data/benchmarks/benchmark_specificity.rb +124 -0
  26. data/benchmarks/benchmark_string_allocation.rb +151 -0
  27. data/benchmarks/benchmark_stylesheet_to_s.rb +62 -0
  28. data/benchmarks/benchmark_to_s_cached.rb +55 -0
  29. data/benchmarks/benchmark_value_splitter.rb +54 -0
  30. data/benchmarks/benchmark_yjit.rb +158 -0
  31. data/benchmarks/benchmark_yjit_workers.rb +61 -0
  32. data/benchmarks/profile_to_s.rb +23 -0
  33. data/benchmarks/speedup_calculator.rb +83 -0
  34. data/benchmarks/system_metadata.rb +81 -0
  35. data/benchmarks/templates/benchmarks.md.erb +221 -0
  36. data/benchmarks/yjit_tests.rb +141 -0
  37. data/cataract.gemspec +34 -0
  38. data/cliff.toml +92 -0
  39. data/examples/color_conversion_visual_test/color_conversion_test.html +3603 -0
  40. data/examples/color_conversion_visual_test/generate.rb +202 -0
  41. data/examples/color_conversion_visual_test/template.html.erb +259 -0
  42. data/examples/css_analyzer/analyzer.rb +164 -0
  43. data/examples/css_analyzer/analyzers/base.rb +33 -0
  44. data/examples/css_analyzer/analyzers/colors.rb +133 -0
  45. data/examples/css_analyzer/analyzers/important.rb +88 -0
  46. data/examples/css_analyzer/analyzers/properties.rb +61 -0
  47. data/examples/css_analyzer/analyzers/specificity.rb +68 -0
  48. data/examples/css_analyzer/templates/report.html.erb +575 -0
  49. data/examples/css_analyzer.rb +69 -0
  50. data/examples/github_analysis.html +5343 -0
  51. data/ext/cataract/cataract.c +1086 -0
  52. data/ext/cataract/cataract.h +174 -0
  53. data/ext/cataract/css_parser.c +1435 -0
  54. data/ext/cataract/extconf.rb +48 -0
  55. data/ext/cataract/import_scanner.c +174 -0
  56. data/ext/cataract/merge.c +973 -0
  57. data/ext/cataract/shorthand_expander.c +902 -0
  58. data/ext/cataract/specificity.c +213 -0
  59. data/ext/cataract/value_splitter.c +116 -0
  60. data/ext/cataract_color/cataract_color.c +16 -0
  61. data/ext/cataract_color/color_conversion.c +1687 -0
  62. data/ext/cataract_color/color_conversion.h +136 -0
  63. data/ext/cataract_color/color_conversion_lab.c +571 -0
  64. data/ext/cataract_color/color_conversion_named.c +259 -0
  65. data/ext/cataract_color/color_conversion_oklab.c +547 -0
  66. data/ext/cataract_color/extconf.rb +23 -0
  67. data/ext/cataract_old/cataract.c +393 -0
  68. data/ext/cataract_old/cataract.h +250 -0
  69. data/ext/cataract_old/css_parser.c +933 -0
  70. data/ext/cataract_old/extconf.rb +67 -0
  71. data/ext/cataract_old/import_scanner.c +174 -0
  72. data/ext/cataract_old/merge.c +776 -0
  73. data/ext/cataract_old/shorthand_expander.c +902 -0
  74. data/ext/cataract_old/specificity.c +213 -0
  75. data/ext/cataract_old/stylesheet.c +290 -0
  76. data/ext/cataract_old/value_splitter.c +116 -0
  77. data/lib/cataract/at_rule.rb +97 -0
  78. data/lib/cataract/color_conversion.rb +18 -0
  79. data/lib/cataract/declarations.rb +332 -0
  80. data/lib/cataract/import_resolver.rb +210 -0
  81. data/lib/cataract/rule.rb +131 -0
  82. data/lib/cataract/stylesheet.rb +716 -0
  83. data/lib/cataract/stylesheet_scope.rb +257 -0
  84. data/lib/cataract/version.rb +5 -0
  85. data/lib/cataract.rb +107 -0
  86. data/lib/tasks/gem.rake +158 -0
  87. data/scripts/fuzzer/run.rb +828 -0
  88. data/scripts/fuzzer/worker.rb +99 -0
  89. data/scripts/generate_benchmarks_md.rb +155 -0
  90. metadata +135 -0
@@ -0,0 +1,259 @@
1
+ // color_conversion_named.c - CSS named color support
2
+ //
3
+ // Implements support for all 147 CSS named colors as defined in:
4
+ // https://www.w3.org/TR/css-color-4/#named-colors
5
+ //
6
+ // Named colors are case-insensitive and map directly to sRGB hex values.
7
+ // Examples: "red" -> #ff0000, "rebeccapurple" -> #663399
8
+ //
9
+ // This file uses a sorted array with binary search for O(log n) lookup.
10
+
11
+ #include "color_conversion.h"
12
+ #include <string.h>
13
+ #include <ctype.h>
14
+
15
+ // Named color entry: color name and its hex RGB value
16
+ struct named_color {
17
+ const char *name;
18
+ unsigned int hex; // RGB as 0xRRGGBB
19
+ };
20
+
21
+ // All 147 CSS named colors, sorted alphabetically for binary search
22
+ // Source: https://www.w3.org/TR/css-color-4/#named-colors
23
+ static const struct named_color NAMED_COLORS[] = {
24
+ {"aliceblue", 0xf0f8ff},
25
+ {"antiquewhite", 0xfaebd7},
26
+ {"aqua", 0x00ffff},
27
+ {"aquamarine", 0x7fffd4},
28
+ {"azure", 0xf0ffff},
29
+ {"beige", 0xf5f5dc},
30
+ {"bisque", 0xffe4c4},
31
+ {"black", 0x000000},
32
+ {"blanchedalmond", 0xffebcd},
33
+ {"blue", 0x0000ff},
34
+ {"blueviolet", 0x8a2be2},
35
+ {"brown", 0xa52a2a},
36
+ {"burlywood", 0xdeb887},
37
+ {"cadetblue", 0x5f9ea0},
38
+ {"chartreuse", 0x7fff00},
39
+ {"chocolate", 0xd2691e},
40
+ {"coral", 0xff7f50},
41
+ {"cornflowerblue", 0x6495ed},
42
+ {"cornsilk", 0xfff8dc},
43
+ {"crimson", 0xdc143c},
44
+ {"cyan", 0x00ffff},
45
+ {"darkblue", 0x00008b},
46
+ {"darkcyan", 0x008b8b},
47
+ {"darkgoldenrod", 0xb8860b},
48
+ {"darkgray", 0xa9a9a9},
49
+ {"darkgreen", 0x006400},
50
+ {"darkgrey", 0xa9a9a9},
51
+ {"darkkhaki", 0xbdb76b},
52
+ {"darkmagenta", 0x8b008b},
53
+ {"darkolivegreen", 0x556b2f},
54
+ {"darkorange", 0xff8c00},
55
+ {"darkorchid", 0x9932cc},
56
+ {"darkred", 0x8b0000},
57
+ {"darksalmon", 0xe9967a},
58
+ {"darkseagreen", 0x8fbc8f},
59
+ {"darkslateblue", 0x483d8b},
60
+ {"darkslategray", 0x2f4f4f},
61
+ {"darkslategrey", 0x2f4f4f},
62
+ {"darkturquoise", 0x00ced1},
63
+ {"darkviolet", 0x9400d3},
64
+ {"deeppink", 0xff1493},
65
+ {"deepskyblue", 0x00bfff},
66
+ {"dimgray", 0x696969},
67
+ {"dimgrey", 0x696969},
68
+ {"dodgerblue", 0x1e90ff},
69
+ {"firebrick", 0xb22222},
70
+ {"floralwhite", 0xfffaf0},
71
+ {"forestgreen", 0x228b22},
72
+ {"fuchsia", 0xff00ff},
73
+ {"gainsboro", 0xdcdcdc},
74
+ {"ghostwhite", 0xf8f8ff},
75
+ {"gold", 0xffd700},
76
+ {"goldenrod", 0xdaa520},
77
+ {"gray", 0x808080},
78
+ {"green", 0x008000},
79
+ {"greenyellow", 0xadff2f},
80
+ {"grey", 0x808080},
81
+ {"honeydew", 0xf0fff0},
82
+ {"hotpink", 0xff69b4},
83
+ {"indianred", 0xcd5c5c},
84
+ {"indigo", 0x4b0082},
85
+ {"ivory", 0xfffff0},
86
+ {"khaki", 0xf0e68c},
87
+ {"lavender", 0xe6e6fa},
88
+ {"lavenderblush", 0xfff0f5},
89
+ {"lawngreen", 0x7cfc00},
90
+ {"lemonchiffon", 0xfffacd},
91
+ {"lightblue", 0xadd8e6},
92
+ {"lightcoral", 0xf08080},
93
+ {"lightcyan", 0xe0ffff},
94
+ {"lightgoldenrodyellow", 0xfafad2},
95
+ {"lightgray", 0xd3d3d3},
96
+ {"lightgreen", 0x90ee90},
97
+ {"lightgrey", 0xd3d3d3},
98
+ {"lightpink", 0xffb6c1},
99
+ {"lightsalmon", 0xffa07a},
100
+ {"lightseagreen", 0x20b2aa},
101
+ {"lightskyblue", 0x87cefa},
102
+ {"lightslategray", 0x778899},
103
+ {"lightslategrey", 0x778899},
104
+ {"lightsteelblue", 0xb0c4de},
105
+ {"lightyellow", 0xffffe0},
106
+ {"lime", 0x00ff00},
107
+ {"limegreen", 0x32cd32},
108
+ {"linen", 0xfaf0e6},
109
+ {"magenta", 0xff00ff},
110
+ {"maroon", 0x800000},
111
+ {"mediumaquamarine", 0x66cdaa},
112
+ {"mediumblue", 0x0000cd},
113
+ {"mediumorchid", 0xba55d3},
114
+ {"mediumpurple", 0x9370db},
115
+ {"mediumseagreen", 0x3cb371},
116
+ {"mediumslateblue", 0x7b68ee},
117
+ {"mediumspringgreen", 0x00fa9a},
118
+ {"mediumturquoise", 0x48d1cc},
119
+ {"mediumvioletred", 0xc71585},
120
+ {"midnightblue", 0x191970},
121
+ {"mintcream", 0xf5fffa},
122
+ {"mistyrose", 0xffe4e1},
123
+ {"moccasin", 0xffe4b5},
124
+ {"navajowhite", 0xffdead},
125
+ {"navy", 0x000080},
126
+ {"oldlace", 0xfdf5e6},
127
+ {"olive", 0x808000},
128
+ {"olivedrab", 0x6b8e23},
129
+ {"orange", 0xffa500},
130
+ {"orangered", 0xff4500},
131
+ {"orchid", 0xda70d6},
132
+ {"palegoldenrod", 0xeee8aa},
133
+ {"palegreen", 0x98fb98},
134
+ {"paleturquoise", 0xafeeee},
135
+ {"palevioletred", 0xdb7093},
136
+ {"papayawhip", 0xffefd5},
137
+ {"peachpuff", 0xffdab9},
138
+ {"peru", 0xcd853f},
139
+ {"pink", 0xffc0cb},
140
+ {"plum", 0xdda0dd},
141
+ {"powderblue", 0xb0e0e6},
142
+ {"purple", 0x800080},
143
+ {"rebeccapurple", 0x663399},
144
+ {"red", 0xff0000},
145
+ {"rosybrown", 0xbc8f8f},
146
+ {"royalblue", 0x4169e1},
147
+ {"saddlebrown", 0x8b4513},
148
+ {"salmon", 0xfa8072},
149
+ {"sandybrown", 0xf4a460},
150
+ {"seagreen", 0x2e8b57},
151
+ {"seashell", 0xfff5ee},
152
+ {"sienna", 0xa0522d},
153
+ {"silver", 0xc0c0c0},
154
+ {"skyblue", 0x87ceeb},
155
+ {"slateblue", 0x6a5acd},
156
+ {"slategray", 0x708090},
157
+ {"slategrey", 0x708090},
158
+ {"snow", 0xfffafa},
159
+ {"springgreen", 0x00ff7f},
160
+ {"steelblue", 0x4682b4},
161
+ {"tan", 0xd2b48c},
162
+ {"teal", 0x008080},
163
+ {"thistle", 0xd8bfd8},
164
+ {"tomato", 0xff6347},
165
+ {"turquoise", 0x40e0d0},
166
+ {"violet", 0xee82ee},
167
+ {"wheat", 0xf5deb3},
168
+ {"white", 0xffffff},
169
+ {"whitesmoke", 0xf5f5f5},
170
+ {"yellow", 0xffff00},
171
+ {"yellowgreen", 0x9acd32}
172
+ };
173
+
174
+ #define NUM_NAMED_COLORS (sizeof(NAMED_COLORS) / sizeof(NAMED_COLORS[0]))
175
+
176
+ // Case-insensitive string comparison for binary search
177
+ static int strcasecmp_limited(const char *a, const char *b, size_t max_len) {
178
+ for (size_t i = 0; i < max_len; i++) {
179
+ if (a[i] == '\0' && b[i] == '\0') return 0;
180
+ if (a[i] == '\0') return -1;
181
+ if (b[i] == '\0') return 1;
182
+
183
+ int diff = tolower((unsigned char)a[i]) - tolower((unsigned char)b[i]);
184
+ if (diff != 0) return diff;
185
+ }
186
+ return 0;
187
+ }
188
+
189
+ // Binary search for named color (case-insensitive)
190
+ // Returns hex value or -1 if not found
191
+ static int lookup_named_color(const char *name, size_t name_len) {
192
+ int left = 0;
193
+ int right = NUM_NAMED_COLORS - 1;
194
+
195
+ DEBUG_PRINTF("lookup: searching for '%.*s' (len=%zu)\n", (int)name_len, name, name_len);
196
+
197
+ while (left <= right) {
198
+ int mid = left + (right - left) / 2;
199
+ int cmp = strcasecmp_limited(name, NAMED_COLORS[mid].name, name_len);
200
+
201
+ DEBUG_PRINTF("lookup: mid=%d, name='%s', cmp=%d\n", mid, NAMED_COLORS[mid].name, cmp);
202
+
203
+ // Also need to check if the matched name is exactly the same length
204
+ if (cmp == 0) {
205
+ // Prefix matches, now check full length
206
+ if (NAMED_COLORS[mid].name[name_len] == '\0') {
207
+ // Exact match!
208
+ DEBUG_PRINTF("lookup: FOUND at mid=%d\n", mid);
209
+ return NAMED_COLORS[mid].hex;
210
+ } else {
211
+ // Prefix matches but array name is longer (e.g., "blue" vs "blueviolet")
212
+ // We want the shorter name, so search left
213
+ right = mid - 1;
214
+ }
215
+ } else if (cmp < 0) {
216
+ right = mid - 1;
217
+ } else {
218
+ left = mid + 1;
219
+ }
220
+ }
221
+
222
+ DEBUG_PRINTF("lookup: NOT FOUND\n");
223
+ return -1; // Not found
224
+ }
225
+
226
+ // Parse named color to IR (sRGB 0-255)
227
+ // Syntax: just the color name (e.g., "red", "rebeccapurple")
228
+ struct color_ir parse_named(VALUE named_value) {
229
+ struct color_ir color;
230
+ INIT_COLOR_IR(color);
231
+
232
+ const char *name = StringValueCStr(named_value);
233
+ size_t name_len = strlen(name);
234
+
235
+ // Trim whitespace
236
+ while (name_len > 0 && isspace((unsigned char)name[name_len - 1])) {
237
+ name_len--;
238
+ }
239
+ while (name_len > 0 && isspace((unsigned char)*name)) {
240
+ name++;
241
+ name_len--;
242
+ }
243
+
244
+ // Look up the color
245
+ int hex = lookup_named_color(name, name_len);
246
+
247
+ if (hex < 0) {
248
+ // Unknown color name - return invalid IR (red = -1 signals invalid)
249
+ color.red = -1;
250
+ return color;
251
+ }
252
+
253
+ // Extract RGB from hex (0xRRGGBB)
254
+ color.red = (hex >> 16) & 0xFF;
255
+ color.green = (hex >> 8) & 0xFF;
256
+ color.blue = hex & 0xFF;
257
+
258
+ return color;
259
+ }