cataract 0.2.4 → 0.3.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +6 -6
  3. data/.gitignore +17 -3
  4. data/.rubocop.yml +1 -0
  5. data/BENCHMARKS.md +24 -6
  6. data/CHANGELOG.md +29 -1
  7. data/Gemfile +2 -2
  8. data/examples/css_analyzer/analyzer.rb +9 -3
  9. data/examples/css_analyzer/analyzers/base.rb +1 -1
  10. data/ext/cataract/cataract.c +251 -458
  11. data/ext/cataract/cataract.h +127 -16
  12. data/ext/cataract/css_parser.c +1029 -700
  13. data/ext/cataract/extconf.rb +1 -2
  14. data/ext/cataract/flatten.c +279 -991
  15. data/ext/cataract/shorthand_expander.c +80 -102
  16. data/ext/cataract_color/color_conversion.c +1 -1
  17. data/lib/cataract/declarations.rb +13 -7
  18. data/lib/cataract/error.rb +49 -0
  19. data/lib/cataract/import_resolver.rb +36 -16
  20. data/lib/cataract/pure/byte_constants.rb +4 -1
  21. data/lib/cataract/pure/flatten.rb +143 -145
  22. data/lib/cataract/pure/parser.rb +623 -388
  23. data/lib/cataract/pure/serializer.rb +109 -104
  24. data/lib/cataract/pure/specificity.rb +112 -156
  25. data/lib/cataract/pure.rb +1 -6
  26. data/lib/cataract/stylesheet.rb +480 -410
  27. data/lib/cataract/version.rb +1 -1
  28. data/lib/cataract.rb +1 -0
  29. metadata +3 -13
  30. data/ext/cataract/import_scanner.c +0 -174
  31. data/ext/cataract_old/cataract.c +0 -393
  32. data/ext/cataract_old/cataract.h +0 -250
  33. data/ext/cataract_old/css_parser.c +0 -933
  34. data/ext/cataract_old/extconf.rb +0 -67
  35. data/ext/cataract_old/import_scanner.c +0 -174
  36. data/ext/cataract_old/merge.c +0 -776
  37. data/ext/cataract_old/shorthand_expander.c +0 -902
  38. data/ext/cataract_old/specificity.c +0 -213
  39. data/ext/cataract_old/stylesheet.c +0 -290
  40. data/ext/cataract_old/value_splitter.c +0 -116
@@ -1,250 +0,0 @@
1
- #ifndef CATARACT_H
2
- #define CATARACT_H
3
-
4
- #include <ruby.h>
5
- #include <ruby/encoding.h>
6
-
7
- // ============================================================================
8
- // Global struct class references (defined in cataract.c, declared extern here)
9
- // ============================================================================
10
-
11
- extern VALUE cDeclaration;
12
- extern VALUE cRule;
13
-
14
- // Error class references
15
- extern VALUE eCataractError;
16
- extern VALUE eParseError;
17
- extern VALUE eDepthError;
18
- extern VALUE eSizeError;
19
-
20
- // ============================================================================
21
- // Struct field indices
22
- // ============================================================================
23
-
24
- // Rule struct field indices (selector, declarations, specificity)
25
- #define RULE_SELECTOR 0
26
- #define RULE_DECLARATIONS 1
27
- #define RULE_SPECIFICITY 2
28
-
29
- // Declaration struct field indices (property, value, important)
30
- #define DECL_PROPERTY 0
31
- #define DECL_VALUE 1
32
- #define DECL_IMPORTANT 2
33
-
34
- // ============================================================================
35
- // Macros
36
- // ============================================================================
37
-
38
- // Whitespace detection
39
- #define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
40
-
41
- // US-ASCII string literal creation (compile-time length for efficiency)
42
- // Use this for string literals like "margin-top" to avoid strlen() at runtime
43
- // Example: USASCII_STR("margin-top") expands to rb_usascii_str_new("margin-top", 10)
44
- #define USASCII_STR(str) rb_usascii_str_new((str), sizeof(str) - 1)
45
-
46
- // UTF-8 string literal creation (compile-time length for efficiency)
47
- // Use this for string literals that may be concatenated with UTF-8 content
48
- // Example: UTF8_STR("@") expands to rb_utf8_str_new("@", 1)
49
- #define UTF8_STR(str) rb_utf8_str_new((str), sizeof(str) - 1)
50
-
51
- // Debug output (disabled by default)
52
- // #define CATARACT_DEBUG 1
53
-
54
- #ifdef CATARACT_DEBUG
55
- #define DEBUG_PRINTF(...) printf(__VA_ARGS__)
56
- #else
57
- #define DEBUG_PRINTF(...) ((void)0)
58
- #endif
59
-
60
- // String allocation optimization (enabled by default)
61
- // Uses rb_str_buf_new for pre-allocation when building selector strings
62
- //
63
- // Disable for benchmarking baseline:
64
- // Development: DISABLE_STR_BUF_OPTIMIZATION=1 rake compile
65
- // Gem install: gem install cataract -- --disable-str-buf-optimization
66
- //
67
- #ifndef DISABLE_STR_BUF_OPTIMIZATION
68
- #define STR_NEW_WITH_CAPACITY(capacity) rb_str_buf_new(capacity)
69
- #define STR_NEW_CSTR(str) rb_str_new_cstr(str)
70
- #else
71
- #define STR_NEW_WITH_CAPACITY(capacity) rb_str_new_cstr("")
72
- #define STR_NEW_CSTR(str) rb_str_new_cstr(str)
73
- #endif
74
-
75
- // Sanity limits for CSS properties and values
76
- // These prevent crashes from pathological inputs (fuzzer-found edge cases)
77
- // Override at compile time if needed: -DMAX_PROPERTY_NAME_LENGTH=512
78
- #ifndef MAX_PROPERTY_NAME_LENGTH
79
- #define MAX_PROPERTY_NAME_LENGTH 256 // Reasonable max for property names (e.g., "background-position-x")
80
- #endif
81
-
82
- #ifndef MAX_PROPERTY_VALUE_LENGTH
83
- #define MAX_PROPERTY_VALUE_LENGTH 32768 // 32KB - handles large data URLs and complex values
84
- #endif
85
-
86
- #ifndef MAX_AT_RULE_BLOCK_LENGTH
87
- #define MAX_AT_RULE_BLOCK_LENGTH 1048576 // 1MB - max size for @media, @supports, etc. block content
88
- #endif
89
-
90
- #ifndef MAX_PARSE_DEPTH
91
- #define MAX_PARSE_DEPTH 10 // Max recursion depth for nested @media/@supports blocks
92
- #endif
93
-
94
- // ============================================================================
95
- // Inline helper functions
96
- // ============================================================================
97
-
98
- // Trim leading whitespace - modifies start pointer
99
- static inline void trim_leading(const char **start, const char *end) {
100
- while (*start < end && IS_WHITESPACE(**start)) {
101
- (*start)++;
102
- }
103
- }
104
-
105
- // Trim trailing whitespace - modifies end pointer
106
- static inline void trim_trailing(const char *start, const char **end) {
107
- while (*end > start && IS_WHITESPACE(*(*end - 1))) {
108
- (*end)--;
109
- }
110
- }
111
-
112
- // Strip whitespace from both ends and return new string
113
- static inline VALUE strip_string(const char *str, long len) {
114
- const char *start = str;
115
- const char *end = str + len;
116
- trim_leading(&start, end);
117
- trim_trailing(start, &end);
118
- return rb_str_new(start, end - start);
119
- }
120
-
121
- // Lowercase property name (CSS property names are ASCII-only)
122
- //
123
- // Performance: Manual loop unrolling (USE_LOOP_UNROLL) provides ~6.6% speedup
124
- // on Apple Silicon M1 (tested with bootstrap.css parsing benchmark).
125
- static inline VALUE lowercase_property(VALUE property_str) {
126
- Check_Type(property_str, T_STRING);
127
-
128
- long len = RSTRING_LEN(property_str);
129
- const char *src = RSTRING_PTR(property_str);
130
-
131
- // Create new US-ASCII string with same length (CSS property names are ASCII-only)
132
- VALUE result = rb_str_buf_new(len);
133
- rb_enc_associate(result, rb_usascii_encoding());
134
-
135
- #ifndef DISABLE_LOOP_UNROLL
136
- // Manual loop unrolling: process 4 chars at a time (default, ~6.6% faster on M1)
137
- // Benefits: Fewer loop iterations, better ILP, fewer rb_str_buf_cat calls
138
- long i = 0;
139
-
140
- // Process 4 characters at a time
141
- for (; i + 3 < len; i += 4) {
142
- char c0 = src[i];
143
- char c1 = src[i+1];
144
- char c2 = src[i+2];
145
- char c3 = src[i+3];
146
-
147
- // Lowercase each character
148
- if (c0 >= 'A' && c0 <= 'Z') c0 += 32;
149
- if (c1 >= 'A' && c1 <= 'Z') c1 += 32;
150
- if (c2 >= 'A' && c2 <= 'Z') c2 += 32;
151
- if (c3 >= 'A' && c3 <= 'Z') c3 += 32;
152
-
153
- char buf[4] = {c0, c1, c2, c3};
154
- rb_str_buf_cat(result, buf, 4);
155
- }
156
-
157
- // Handle remaining characters (0-3)
158
- for (; i < len; i++) {
159
- char c = src[i];
160
- if (c >= 'A' && c <= 'Z') {
161
- c += 32;
162
- }
163
- rb_str_buf_cat(result, &c, 1);
164
- }
165
- #else
166
- // Unrolling disabled: process one character at a time
167
- for (long i = 0; i < len; i++) {
168
- char c = src[i];
169
- // Lowercase ASCII letters only (CSS properties are ASCII)
170
- if (c >= 'A' && c <= 'Z') {
171
- c = c + ('a' - 'A');
172
- }
173
- rb_str_buf_cat(result, &c, 1);
174
- }
175
- #endif
176
-
177
- return result;
178
- }
179
-
180
- // ============================================================================
181
- // Function declarations (implemented in various .c/.rl files)
182
- // ============================================================================
183
-
184
- // Serialization functions (cataract.c)
185
- // Helper function for internal use (called by stylesheet.c)
186
- VALUE declarations_array_to_s(VALUE declarations_array);
187
-
188
- // Stylesheet serialization (stylesheet.c)
189
- VALUE stylesheet_to_s_c(VALUE self, VALUE rules_array, VALUE charset);
190
- VALUE stylesheet_to_formatted_s_c(VALUE self, VALUE rules_array, VALUE charset);
191
-
192
- // Import scanning (import_scanner.c)
193
- VALUE extract_imports(VALUE self, VALUE css_string);
194
-
195
- // Merge/cascade functions (merge.c)
196
- void init_merge_constants(void);
197
- VALUE cataract_merge(VALUE self, VALUE rules_array);
198
- VALUE cataract_merge_wrapper(VALUE self, VALUE input);
199
-
200
- // Shorthand expansion (shorthand_expander.rl)
201
- VALUE cataract_split_value(VALUE self, VALUE value);
202
- VALUE cataract_expand_margin(VALUE self, VALUE value);
203
- VALUE cataract_expand_padding(VALUE self, VALUE value);
204
- VALUE cataract_expand_border_color(VALUE self, VALUE value);
205
- VALUE cataract_expand_border_style(VALUE self, VALUE value);
206
- VALUE cataract_expand_border_width(VALUE self, VALUE value);
207
- VALUE cataract_expand_border(VALUE self, VALUE value);
208
- VALUE cataract_expand_border_side(VALUE self, VALUE side, VALUE value);
209
- VALUE cataract_expand_font(VALUE self, VALUE value);
210
- VALUE cataract_expand_list_style(VALUE self, VALUE value);
211
- VALUE cataract_expand_background(VALUE self, VALUE value);
212
-
213
- // Shorthand creation (shorthand_expander.rl)
214
- VALUE cataract_create_margin_shorthand(VALUE self, VALUE properties);
215
- VALUE cataract_create_padding_shorthand(VALUE self, VALUE properties);
216
- VALUE cataract_create_border_width_shorthand(VALUE self, VALUE properties);
217
- VALUE cataract_create_border_style_shorthand(VALUE self, VALUE properties);
218
- VALUE cataract_create_border_color_shorthand(VALUE self, VALUE properties);
219
- VALUE cataract_create_border_shorthand(VALUE self, VALUE properties);
220
- VALUE cataract_create_background_shorthand(VALUE self, VALUE properties);
221
- VALUE cataract_create_font_shorthand(VALUE self, VALUE properties);
222
- VALUE cataract_create_list_style_shorthand(VALUE self, VALUE properties);
223
-
224
- // CSS parser implementation (css_parser.c)
225
- VALUE parse_css_impl(VALUE css_string, int depth, VALUE parent_media_query);
226
-
227
- // CSS parsing helper functions (css_parser.c)
228
- VALUE parse_media_query(const char *query_str, long query_len);
229
- VALUE parse_declarations_string(const char *start, const char *end);
230
- void capture_declarations_fn(
231
- const char **decl_start_ptr,
232
- const char *p,
233
- VALUE *current_declarations,
234
- const char *css_string_base
235
- );
236
- void finish_rule_fn(
237
- int inside_at_rule_block,
238
- VALUE *current_selectors,
239
- VALUE *current_declarations,
240
- VALUE *current_media_types,
241
- VALUE rules_array,
242
- const char **mark_ptr
243
- );
244
-
245
- // Specificity calculator (specificity.c)
246
- VALUE calculate_specificity(VALUE self, VALUE selector_string);
247
-
248
- // NOTE: Color conversion moved to separate extension (ext/cataract_color/)
249
-
250
- #endif // CATARACT_H