home
readme
diff
tree
note
docs
0commit 8d8a7243f03d1d683d9235f4a183e8a2c0594bb6
1Author: lakefox <mason@lakefox.net>
2Date: Fri Jan 23 16:24:22 2026 -0700
3
4 If added
5
6diff --git a/:w b/:w
7deleted file mode 100644
8index de2bf61..0000000
9--- a/:w
10+++ /dev/null
11@@ -1,1748 +0,0 @@
12-#include "grim.h"
13-#include <iostream>
14-#include <fstream>
15-#include <sstream>
16-#include <unordered_map>
17-#include <cctype>
18-#include <algorithm>
19-#include <cmath>
20-#include <string_view>
21-
22-struct SymbolTable {
23- std::unordered_map<std::string, int> table{};
24- int next = 5;
25-
26- int get(std::string_view name) {
27- auto it = table.find(std::string(name));
28- if (it != table.end()) return it->second;
29-
30- int id = next++;
31- table[std::string(name)] = id;
32- return id;
33- }
34-};
35-
36-std::unordered_map<std::string, std::string> parseAttributes(std::string_view token) {
37- std::unordered_map<std::string, std::string> attrs;
38-
39- bool inQuote = false;
40- bool escaped = false;
41- char quoteType = '"';
42-
43- std::string word;
44- for (unsigned short i = 0; i < token.length(); i++) {
45- char current = token[i];
46- if ((current == '"' || current == '\'') && !escaped) {
47- if (inQuote && current == quoteType) {
48- inQuote = false;
49- } else if (!inQuote) {
50- inQuote = true;
51- quoteType = current;
52- }
53- }
54-
55- if (current == '\\') { //'
56- escaped = true;
57- continue;
58- }
59-
60- if ((!std::isspace(current) || inQuote) && i != token.length()-1) {
61- word += current;
62- } else {
63- if (i == token.length()-1) {
64- word += current;
65- }
66-
67- std::string name = "";
68- std::string value = "";
69- bool setValue = false;
70-
71- for (auto c : word) {
72- if (c == '=') {
73- setValue = true;
74- continue;
75- }
76-
77- if (setValue) {
78- value += c;
79- } else {
80- name += c;
81- }
82- }
83-
84- word = "";
85-
86- std::string trimmedName = "";
87- for (auto c : name) {
88- if (!std::isspace(c)) {
89- trimmedName += c;
90- }
91- }
92-
93- if (attrs.size() == 0) {
94- value = '"'+trimmedName+'"';
95- trimmedName = "tagName";
96- }
97-
98- std::string trimmedValue = "";
99- int sliceStart = 0;
100- int sliceEnd = value.length();
101-
102- if (value.length() >= 2) {
103- for (unsigned short t = 0; t < value.length(); t++) {
104- if (!std::isspace(value[t])) {
105- sliceStart = t;
106- break;
107- }
108- }
109-
110- for (int t = value.length()-1; t >= 0; t--) {
111- // Trim the trailing / on self closing elements if there isn't a space in between
112- if (!std::isspace(value[t]) && value[t] != '/') {
113- sliceEnd = t;
114- break;
115- }
116- }
117-
118- // Add and subtract 1 from each side to remove quotes
119- for (unsigned short t = sliceStart+1; t < sliceEnd; t++) {
120- trimmedValue += value[t];
121- }
122- }
123-
124- if (trimmedValue.length() == 0) {
125- trimmedValue = "";
126- }
127-
128- attrs[trimmedName] = trimmedValue;
129- }
130- }
131-
132- return attrs;
133-}
134-
135-static const std::unordered_map<std::string, KeyType> keySearch {
136- {"accent-color", KeyType::ACCENT_COLOR},
137- {"align-content", KeyType::ALIGN_CONTENT},
138- {"align-items", KeyType::ALIGN_ITEMS},
139- {"align-self", KeyType::ALIGN_SELF},
140- {"alignment-baseline", KeyType::ALIGNMENT_BASELINE},
141- {"all", KeyType::ALL},
142- {"anchor-name", KeyType::ANCHOR_NAME},
143- {"animation-composition", KeyType::ANIMATION_COMPOSITION},
144- {"animation-delay", KeyType::ANIMATION_DELAY},
145- {"animation-direction", KeyType::ANIMATION_DIRECTION},
146- {"animation-duration", KeyType::ANIMATION_DURATION},
147- {"animation-fill-mode", KeyType::ANIMATION_FILL_MODE},
148- {"animation-iteration-count", KeyType::ANIMATION_ITERATION_COUNT},
149- {"animation-name", KeyType::ANIMATION_NAME},
150- {"animation-play-state", KeyType::ANIMATION_PLAY_STATE},
151- {"animation-range-end", KeyType::ANIMATION_RANGE_END},
152- {"animation-range-start", KeyType::ANIMATION_RANGE_START},
153- {"animation-range", KeyType::ANIMATION_RANGE},
154- {"animation-timeline", KeyType::ANIMATION_TIMELINE},
155- {"animation-timing-function", KeyType::ANIMATION_TIMING_FUNCTION},
156- {"animation", KeyType::ANIMATION},
157- {"appearance", KeyType::APPEARANCE},
158- {"aspect-ratio", KeyType::ASPECT_RATIO},
159- {"backdrop-filter", KeyType::BACKDROP_FILTER},
160- {"backface-visibility", KeyType::BACKFACE_VISIBILITY},
161- {"background-attachment", KeyType::BACKGROUND_ATTACHMENT},
162- {"background-blend-mode", KeyType::BACKGROUND_BLEND_MODE},
163- {"background-clip", KeyType::BACKGROUND_CLIP},
164- {"background-color", KeyType::BACKGROUND_COLOR},
165- {"background-image", KeyType::BACKGROUND_IMAGE},
166- {"background-origin", KeyType::BACKGROUND_ORIGIN},
167- {"background-position-x", KeyType::BACKGROUND_POSITION_X},
168- {"background-position-y", KeyType::BACKGROUND_POSITION_Y},
169- {"background-position", KeyType::BACKGROUND_POSITION},
170- {"background-repeat", KeyType::BACKGROUND_REPEAT},
171- {"background-size", KeyType::BACKGROUND_SIZE},
172- {"background", KeyType::BACKGROUND},
173- {"block-size", KeyType::BLOCK_SIZE},
174- {"border-block-color", KeyType::BORDER_BLOCK_COLOR},
175- {"border-block-end-color", KeyType::BORDER_BLOCK_END_COLOR},
176- {"border-block-end-style", KeyType::BORDER_BLOCK_END_STYLE},
177- {"border-block-end-width", KeyType::BORDER_BLOCK_END_WIDTH},
178- {"border-block-end", KeyType::BORDER_BLOCK_END},
179- {"border-block-start-color", KeyType::BORDER_BLOCK_START_COLOR},
180- {"border-block-start-style", KeyType::BORDER_BLOCK_START_STYLE},
181- {"border-block-start-width", KeyType::BORDER_BLOCK_START_WIDTH},
182- {"border-block-start", KeyType::BORDER_BLOCK_START},
183- {"border-block-style", KeyType::BORDER_BLOCK_STYLE},
184- {"border-block-width", KeyType::BORDER_BLOCK_WIDTH},
185- {"border-block", KeyType::BORDER_BLOCK},
186- {"border-bottom-color", KeyType::BORDER_BOTTOM_COLOR},
187- {"border-bottom-left-radius", KeyType::BORDER_BOTTOM_LEFT_RADIUS},
188- {"border-bottom-right-radius", KeyType::BORDER_BOTTOM_RIGHT_RADIUS},
189- {"border-bottom-style", KeyType::BORDER_BOTTOM_STYLE},
190- {"border-bottom-width", KeyType::BORDER_BOTTOM_WIDTH},
191- {"border-bottom", KeyType::BORDER_BOTTOM},
192- {"border-collapse", KeyType::BORDER_COLLAPSE},
193- {"border-color", KeyType::BORDER_COLOR},
194- {"border-end-end-radius", KeyType::BORDER_END_END_RADIUS},
195- {"border-end-start-radius", KeyType::BORDER_END_START_RADIUS},
196- {"border-image-outset", KeyType::BORDER_IMAGE_OUTSET},
197- {"border-image-repeat", KeyType::BORDER_IMAGE_REPEAT},
198- {"border-image-slice", KeyType::BORDER_IMAGE_SLICE},
199- {"border-image-source", KeyType::BORDER_IMAGE_SOURCE},
200- {"border-image-width", KeyType::BORDER_IMAGE_WIDTH},
201- {"border-image", KeyType::BORDER_IMAGE},
202- {"border-inline-color", KeyType::BORDER_INLINE_COLOR},
203- {"border-inline-end-color", KeyType::BORDER_INLINE_END_COLOR},
204- {"border-inline-end-style", KeyType::BORDER_INLINE_END_STYLE},
205- {"border-inline-end-width", KeyType::BORDER_INLINE_END_WIDTH},
206- {"border-inline-end", KeyType::BORDER_INLINE_END},
207- {"border-inline-start-color", KeyType::BORDER_INLINE_START_COLOR},
208- {"border-inline-start-style", KeyType::BORDER_INLINE_START_STYLE},
209- {"border-inline-start-width", KeyType::BORDER_INLINE_START_WIDTH},
210- {"border-inline-start", KeyType::BORDER_INLINE_START},
211- {"border-inline-style", KeyType::BORDER_INLINE_STYLE},
212- {"border-inline-width", KeyType::BORDER_INLINE_WIDTH},
213- {"border-inline", KeyType::BORDER_INLINE},
214- {"border-left-color", KeyType::BORDER_LEFT_COLOR},
215- {"border-left-style", KeyType::BORDER_LEFT_STYLE},
216- {"border-left-width", KeyType::BORDER_LEFT_WIDTH},
217- {"border-left", KeyType::BORDER_LEFT},
218- {"border-radius", KeyType::BORDER_RADIUS},
219- {"border-right-color", KeyType::BORDER_RIGHT_COLOR},
220- {"border-right-style", KeyType::BORDER_RIGHT_STYLE},
221- {"border-right-width", KeyType::BORDER_RIGHT_WIDTH},
222- {"border-right", KeyType::BORDER_RIGHT},
223- {"border-spacing", KeyType::BORDER_SPACING},
224- {"border-start-end-radius", KeyType::BORDER_START_END_RADIUS},
225- {"border-start-start-radius", KeyType::BORDER_START_START_RADIUS},
226- {"border-style", KeyType::BORDER_STYLE},
227- {"border-top-color", KeyType::BORDER_TOP_COLOR},
228- {"border-top-left-radius", KeyType::BORDER_TOP_LEFT_RADIUS},
229- {"border-top-right-radius", KeyType::BORDER_TOP_RIGHT_RADIUS},
230- {"border-top-style", KeyType::BORDER_TOP_STYLE},
231- {"border-top-width", KeyType::BORDER_TOP_WIDTH},
232- {"border-top", KeyType::BORDER_TOP},
233- {"border-width", KeyType::BORDER_WIDTH},
234- {"border", KeyType::BORDER},
235- {"bottom", KeyType::BOTTOM},
236- {"box-align", KeyType::BOX_ALIGN},
237- {"box-decoration-break", KeyType::BOX_DECORATION_BREAK},
238- {"box-direction", KeyType::BOX_DIRECTION},
239- {"box-flex-group", KeyType::BOX_FLEX_GROUP},
240- {"box-flex", KeyType::BOX_FLEX},
241- {"box-lines", KeyType::BOX_LINES},
242- {"box-ordinal-group", KeyType::BOX_ORDINAL_GROUP},
243- {"box-orient", KeyType::BOX_ORIENT},
244- {"box-pack", KeyType::BOX_PACK},
245- {"box-shadow", KeyType::BOX_SHADOW},
246- {"box-sizing", KeyType::BOX_SIZING},
247- {"break-after", KeyType::BREAK_AFTER},
248- {"break-before", KeyType::BREAK_BEFORE},
249- {"break-inside", KeyType::BREAK_INSIDE},
250- {"caption-side", KeyType::CAPTION_SIDE},
251- {"caret-color", KeyType::CARET_COLOR},
252- {"clear", KeyType::CLEAR},
253- {"clip-path", KeyType::CLIP_PATH},
254- {"clip-rule", KeyType::CLIP_RULE},
255- {"clip", KeyType::CLIP},
256- {"color-interpolation-filters", KeyType::COLOR_INTERPOLATION_FILTERS},
257- {"color-interpolation", KeyType::COLOR_INTERPOLATION},
258- {"color-scheme", KeyType::COLOR_SCHEME},
259- {"color", KeyType::COLOR},
260- {"column-count", KeyType::COLUMN_COUNT},
261- {"column-fill", KeyType::COLUMN_FILL},
262- {"column-gap", KeyType::COLUMN_GAP},
263- {"column-rule-color", KeyType::COLUMN_RULE_COLOR},
264- {"column-rule-style", KeyType::COLUMN_RULE_STYLE},
265- {"column-rule-width", KeyType::COLUMN_RULE_WIDTH},
266- {"column-rule", KeyType::COLUMN_RULE},
267- {"column-span", KeyType::COLUMN_SPAN},
268- {"column-width", KeyType::COLUMN_WIDTH},
269- {"columns", KeyType::COLUMNS},
270- {"contain-intrinsic-block-size", KeyType::CONTAIN_INTRINSIC_BLOCK_SIZE},
271- {"contain-intrinsic-height", KeyType::CONTAIN_INTRINSIC_HEIGHT},
272- {"contain-intrinsic-inline-size", KeyType::CONTAIN_INTRINSIC_INLINE_SIZE},
273- {"contain-intrinsic-size", KeyType::CONTAIN_INTRINSIC_SIZE},
274- {"contain-intrinsic-width", KeyType::CONTAIN_INTRINSIC_WIDTH},
275- {"contain", KeyType::CONTAIN},
276- {"container-name", KeyType::CONTAINER_NAME},
277- {"container-type", KeyType::CONTAINER_TYPE},
278- {"container", KeyType::CONTAINER},
279- {"content-visibility", KeyType::CONTENT_VISIBILITY},
280- {"content", KeyType::CONTENT},
281- {"counter-increment", KeyType::COUNTER_INCREMENT},
282- {"counter-reset", KeyType::COUNTER_RESET},
283- {"counter-set", KeyType::COUNTER_SET},
284- {"cursor", KeyType::CURSOR},
285- {"cx", KeyType::CX},
286- {"cy", KeyType::CY},
287- {"d", KeyType::D},
288- {"direction", KeyType::DIRECTION},
289- {"display", KeyType::DISPLAY},
290- {"dominant-baseline", KeyType::DOMINANT_BASELINE},
291- {"empty-cells", KeyType::EMPTY_CELLS},
292- {"field-sizing", KeyType::FIELD_SIZING},
293- {"fill-opacity", KeyType::FILL_OPACITY},
294- {"fill-rule", KeyType::FILL_RULE},
295- {"fill", KeyType::FILL},
296- {"filter", KeyType::FILTER},
297- {"flex-basis", KeyType::FLEX_BASIS},
298- {"flex-direction", KeyType::FLEX_DIRECTION},
299- {"flex-flow", KeyType::FLEX_FLOW},
300- {"flex-grow", KeyType::FLEX_GROW},
301- {"flex-shrink", KeyType::FLEX_SHRINK},
302- {"flex-wrap", KeyType::FLEX_WRAP},
303- {"flex", KeyType::FLEX},
304- {"float", KeyType::FLOAT},
305- {"flood-color", KeyType::FLOOD_COLOR},
306- {"flood-opacity", KeyType::FLOOD_OPACITY},
307- {"font-family", KeyType::FONT_FAMILY},
308- {"font-feature-settings", KeyType::FONT_FEATURE_SETTINGS},
309- {"font-kerning", KeyType::FONT_KERNING},
310- {"font-language-override", KeyType::FONT_LANGUAGE_OVERRIDE},
311- {"font-optical-sizing", KeyType::FONT_OPTICAL_SIZING},
312- {"font-palette", KeyType::FONT_PALETTE},
313- {"font-size-adjust", KeyType::FONT_SIZE_ADJUST},
314- {"font-size", KeyType::FONT_SIZE},
315- {"font-smooth", KeyType::FONT_SMOOTH},
316- {"font-stretch", KeyType::FONT_STRETCH},
317- {"font-style", KeyType::FONT_STYLE},
318- {"font-synthesis-position", KeyType::FONT_SYNTHESIS_POSITION},
319- {"font-synthesis-small-caps", KeyType::FONT_SYNTHESIS_SMALL_CAPS},
320- {"font-synthesis-style", KeyType::FONT_SYNTHESIS_STYLE},
321- {"font-synthesis-weight", KeyType::FONT_SYNTHESIS_WEIGHT},
322- {"font-synthesis", KeyType::FONT_SYNTHESIS},
323- {"font-variant-alternates", KeyType::FONT_VARIANT_ALTERNATES},
324- {"font-variant-caps", KeyType::FONT_VARIANT_CAPS},
325- {"font-variant-east-asian", KeyType::FONT_VARIANT_EAST_ASIAN},
326- {"font-variant-emoji", KeyType::FONT_VARIANT_EMOJI},
327- {"font-variant-ligatures", KeyType::FONT_VARIANT_LIGATURES},
328- {"font-variant-numeric", KeyType::FONT_VARIANT_NUMERIC},
329- {"font-variant-position", KeyType::FONT_VARIANT_POSITION},
330- {"font-variant", KeyType::FONT_VARIANT},
331- {"font-variation-settings", KeyType::FONT_VARIATION_SETTINGS},
332- {"font-weight", KeyType::FONT_WEIGHT},
333- {"font", KeyType::FONT},
334- {"forced-color-adjust", KeyType::FORCED_COLOR_ADJUST},
335- {"gap", KeyType::GAP},
336- {"grid-area", KeyType::GRID_AREA},
337- {"grid-auto-columns", KeyType::GRID_AUTO_COLUMNS},
338- {"grid-auto-flow", KeyType::GRID_AUTO_FLOW},
339- {"grid-auto-rows", KeyType::GRID_AUTO_ROWS},
340- {"grid-column-end", KeyType::GRID_COLUMN_END},
341- {"grid-column-start", KeyType::GRID_COLUMN_START},
342- {"grid-column", KeyType::GRID_COLUMN},
343- {"grid-row-end", KeyType::GRID_ROW_END},
344- {"grid-row-start", KeyType::GRID_ROW_START},
345- {"grid-row", KeyType::GRID_ROW},
346- {"grid-template-areas", KeyType::GRID_TEMPLATE_AREAS},
347- {"grid-template-columns", KeyType::GRID_TEMPLATE_COLUMNS},
348- {"grid-template-rows", KeyType::GRID_TEMPLATE_ROWS},
349- {"grid-template", KeyType::GRID_TEMPLATE},
350- {"grid", KeyType::GRID},
351- {"hanging-punctuation", KeyType::HANGING_PUNCTUATION},
352- {"height", KeyType::HEIGHT},
353- {"hyphenate-character", KeyType::HYPHENATE_CHARACTER},
354- {"hyphenate-limit-chars", KeyType::HYPHENATE_LIMIT_CHARS},
355- {"hyphens", KeyType::HYPHENS},
356- {"image-orientation", KeyType::IMAGE_ORIENTATION},
357- {"image-rendering", KeyType::IMAGE_RENDERING},
358- {"image-resolution", KeyType::IMAGE_RESOLUTION},
359- {"initial-letter", KeyType::INITIAL_LETTER},
360- {"inline-size", KeyType::INLINE_SIZE},
361- {"inset-block-end", KeyType::INSET_BLOCK_END},
362- {"inset-block-start", KeyType::INSET_BLOCK_START},
363- {"inset-block", KeyType::INSET_BLOCK},
364- {"inset-block", KeyType::INSET_BLOCK},
365- {"inset-inline-end", KeyType::INSET_INLINE_END},
366- {"inset-inline-start", KeyType::INSET_INLINE_START},
367- {"inset-inline", KeyType::INSET_INLINE},
368- {"inset-inline", KeyType::INSET_INLINE},
369- {"inset", KeyType::INSET},
370- {"inset", KeyType::INSET},
371- {"interpolate-size", KeyType::INTERPOLATE_SIZE},
372- {"isolation", KeyType::ISOLATION},
373- {"justify-content", KeyType::JUSTIFY_CONTENT},
374- {"justify-items", KeyType::JUSTIFY_ITEMS},
375- {"justify-self", KeyType::JUSTIFY_SELF},
376- {"left", KeyType::LEFT},
377- {"letter-spacing", KeyType::LETTER_SPACING},
378- {"lighting-color", KeyType::LIGHTING_COLOR},
379- {"line-break", KeyType::LINE_BREAK},
380- {"line-clamp", KeyType::LINE_CLAMP},
381- {"line-height-step", KeyType::LINE_HEIGHT_STEP},
382- {"line-height", KeyType::LINE_HEIGHT},
383- {"list-style-image", KeyType::LIST_STYLE_IMAGE},
384- {"list-style-position", KeyType::LIST_STYLE_POSITION},
385- {"list-style-type", KeyType::LIST_STYLE_TYPE},
386- {"list-style", KeyType::LIST_STYLE},
387- {"list-style", KeyType::LIST_STYLE},
388- {"margin-block-end", KeyType::MARGIN_BLOCK_END},
389- {"margin-block-start", KeyType::MARGIN_BLOCK_START},
390- {"margin-block", KeyType::MARGIN_BLOCK},
391- {"margin-bottom", KeyType::MARGIN_BOTTOM},
392- {"margin-inline-end", KeyType::MARGIN_INLINE_END},
393- {"margin-inline-start", KeyType::MARGIN_INLINE_START},
394- {"margin-inline", KeyType::MARGIN_INLINE},
395- {"margin-left", KeyType::MARGIN_LEFT},
396- {"margin-right", KeyType::MARGIN_RIGHT},
397- {"margin-top", KeyType::MARGIN_TOP},
398- {"margin-trim", KeyType::MARGIN_TRIM},
399- {"margin", KeyType::MARGIN},
400- {"marker-end", KeyType::MARKER_END},
401- {"marker-mid", KeyType::MARKER_MID},
402- {"marker-start", KeyType::MARKER_START},
403- {"marker", KeyType::MARKER},
404- {"mask-border-mode", KeyType::MASK_BORDER_MODE},
405- {"mask-border-outset", KeyType::MASK_BORDER_OUTSET},
406- {"mask-border-repeat", KeyType::MASK_BORDER_REPEAT},
407- {"mask-border-slice", KeyType::MASK_BORDER_SLICE},
408- {"mask-border-source", KeyType::MASK_BORDER_SOURCE},
409- {"mask-border-width", KeyType::MASK_BORDER_WIDTH},
410- {"mask-border", KeyType::MASK_BORDER},
411- {"mask-clip", KeyType::MASK_CLIP},
412- {"mask-composite", KeyType::MASK_COMPOSITE},
413- {"mask-image", KeyType::MASK_IMAGE},
414- {"mask-mode", KeyType::MASK_MODE},
415- {"mask-origin", KeyType::MASK_ORIGIN},
416- {"mask-position", KeyType::MASK_POSITION},
417- {"mask-repeat", KeyType::MASK_REPEAT},
418- {"mask-size", KeyType::MASK_SIZE},
419- {"mask-type", KeyType::MASK_TYPE},
420- {"mask", KeyType::MASK},
421- {"math-depth", KeyType::MATH_DEPTH},
422- {"math-shift", KeyType::MATH_SHIFT},
423- {"math-style", KeyType::MATH_STYLE},
424- {"max-block-size", KeyType::MAX_BLOCK_SIZE},
425- {"max-height", KeyType::MAX_HEIGHT},
426- {"max-inline-size", KeyType::MAX_INLINE_SIZE},
427- {"max-width", KeyType::MAX_WIDTH},
428- {"min-block-size", KeyType::MIN_BLOCK_SIZE},
429- {"min-height", KeyType::MIN_HEIGHT},
430- {"min-inline-size", KeyType::MIN_INLINE_SIZE},
431- {"min-width", KeyType::MIN_WIDTH},
432- {"mix-blend-mode", KeyType::MIX_BLEND_MODE},
433- {"object-fit", KeyType::OBJECT_FIT},
434- {"object-position", KeyType::OBJECT_POSITION},
435- {"offset-anchor", KeyType::OFFSET_ANCHOR},
436- {"offset-distance", KeyType::OFFSET_DISTANCE},
437- {"offset-path", KeyType::OFFSET_PATH},
438- {"offset-position", KeyType::OFFSET_POSITION},
439- {"offset-rotate", KeyType::OFFSET_ROTATE},
440- {"offset", KeyType::OFFSET},
441- {"opacity", KeyType::OPACITY},
442- {"order", KeyType::ORDER},
443- {"orphans", KeyType::ORPHANS},
444- {"outline-color", KeyType::OUTLINE_COLOR},
445- {"outline-offset", KeyType::OUTLINE_OFFSET},
446- {"outline-style", KeyType::OUTLINE_STYLE},
447- {"outline-width", KeyType::OUTLINE_WIDTH},
448- {"outline", KeyType::OUTLINE},
449- {"overflow-anchor", KeyType::OVERFLOW_ANCHOR},
450- {"overflow-block", KeyType::OVERFLOW_BLOCK},
451- {"overflow-clip-margin", KeyType::OVERFLOW_CLIP_MARGIN},
452- {"overflow-inline", KeyType::OVERFLOW_INLINE},
453- {"overflow-wrap", KeyType::OVERFLOW_WRAP},
454- {"overflow-x", KeyType::OVERFLOW_X},
455- {"overflow-y", KeyType::OVERFLOW_Y},
456- {"overflow", KeyType::OVERFLOW},
457- {"overlay", KeyType::OVERLAY},
458- {"overscroll-behavior-block", KeyType::OVERSCROLL_BEHAVIOR_BLOCK},
459- {"overscroll-behavior-inline", KeyType::OVERSCROLL_BEHAVIOR_INLINE},
460- {"overscroll-behavior-x", KeyType::OVERSCROLL_BEHAVIOR_X},
461- {"overscroll-behavior-y", KeyType::OVERSCROLL_BEHAVIOR_Y},
462- {"overscroll-behavior", KeyType::OVERSCROLL_BEHAVIOR},
463- {"padding-block-end", KeyType::PADDING_BLOCK_END},
464- {"padding-block-start", KeyType::PADDING_BLOCK_START},
465- {"padding-block", KeyType::PADDING_BLOCK},
466- {"padding-bottom", KeyType::PADDING_BOTTOM},
467- {"padding-inline-end", KeyType::PADDING_INLINE_END},
468- {"padding-inline-start", KeyType::PADDING_INLINE_START},
469- {"padding-inline", KeyType::PADDING_INLINE},
470- {"padding-left", KeyType::PADDING_LEFT},
471- {"padding-right", KeyType::PADDING_RIGHT},
472- {"padding-top", KeyType::PADDING_TOP},
473- {"padding", KeyType::PADDING},
474- {"page-break-after", KeyType::PAGE_BREAK_AFTER},
475- {"page-break-before", KeyType::PAGE_BREAK_BEFORE},
476- {"page-break-inside", KeyType::PAGE_BREAK_INSIDE},
477- {"page", KeyType::PAGE},
478- {"paint-order", KeyType::PAINT_ORDER},
479- {"perspective-origin", KeyType::PERSPECTIVE_ORIGIN},
480- {"perspective", KeyType::PERSPECTIVE},
481- {"place-content", KeyType::PLACE_CONTENT},
482- {"place-items", KeyType::PLACE_ITEMS},
483- {"place-self", KeyType::PLACE_SELF},
484- {"pointer-events", KeyType::POINTER_EVENTS},
485- {"position-anchor", KeyType::POSITION_ANCHOR},
486- {"position-area", KeyType::POSITION_AREA},
487- {"position-try-fallbacks", KeyType::POSITION_TRY_FALLBACKS},
488- {"position-try-order", KeyType::POSITION_TRY_ORDER},
489- {"position-try", KeyType::POSITION_TRY},
490- {"position-visibility", KeyType::POSITION_VISIBILITY},
491- {"position", KeyType::POSITION},
492- {"print-color-adjust", KeyType::PRINT_COLOR_ADJUST},
493- {"quotes", KeyType::QUOTES},
494- {"r", KeyType::R},
495- {"reading-flow", KeyType::READING_FLOW},
496- {"reading-order", KeyType::READING_ORDER},
497- {"resize", KeyType::RESIZE},
498- {"right", KeyType::RIGHT},
499- {"rotate", KeyType::ROTATE},
500- {"row-gap", KeyType::ROW_GAP},
501- {"ruby-align", KeyType::RUBY_ALIGN},
502- {"ruby-position", KeyType::RUBY_POSITION},
503- {"rx", KeyType::RX},
504- {"ry", KeyType::RY},
505- {"scale", KeyType::SCALE},
506- {"scroll-behavior", KeyType::SCROLL_BEHAVIOR},
507- {"scroll-margin-block-end", KeyType::SCROLL_MARGIN_BLOCK_END},
508- {"scroll-margin-block-start", KeyType::SCROLL_MARGIN_BLOCK_START},
509- {"scroll-margin-block", KeyType::SCROLL_MARGIN_BLOCK},
510- {"scroll-margin-bottom", KeyType::SCROLL_MARGIN_BOTTOM},
511- {"scroll-margin-inline-end", KeyType::SCROLL_MARGIN_INLINE_END},
512- {"scroll-margin-inline-start", KeyType::SCROLL_MARGIN_INLINE_START},
513- {"scroll-margin-inline", KeyType::SCROLL_MARGIN_INLINE},
514- {"scroll-margin-left", KeyType::SCROLL_MARGIN_LEFT},
515- {"scroll-margin-right", KeyType::SCROLL_MARGIN_RIGHT},
516- {"scroll-margin-top", KeyType::SCROLL_MARGIN_TOP},
517- {"scroll-margin", KeyType::SCROLL_MARGIN},
518- {"scroll-marker-group", KeyType::SCROLL_MARKER_GROUP},
519- {"scroll-padding-block-end", KeyType::SCROLL_PADDING_BLOCK_END},
520- {"scroll-padding-block-start", KeyType::SCROLL_PADDING_BLOCK_START},
521- {"scroll-padding-block", KeyType::SCROLL_PADDING_BLOCK},
522- {"scroll-padding-bottom", KeyType::SCROLL_PADDING_BOTTOM},
523- {"scroll-padding-inline-end", KeyType::SCROLL_PADDING_INLINE_END},
524- {"scroll-padding-inline-start", KeyType::SCROLL_PADDING_INLINE_START},
525- {"scroll-padding-inline", KeyType::SCROLL_PADDING_INLINE},
526- {"scroll-padding-left", KeyType::SCROLL_PADDING_LEFT},
527- {"scroll-padding-right", KeyType::SCROLL_PADDING_RIGHT},
528- {"scroll-padding-top", KeyType::SCROLL_PADDING_TOP},
529- {"scroll-padding", KeyType::SCROLL_PADDING},
530- {"scroll-snap-align", KeyType::SCROLL_SNAP_ALIGN},
531- {"scroll-snap-stop", KeyType::SCROLL_SNAP_STOP},
532- {"scroll-snap-type", KeyType::SCROLL_SNAP_TYPE},
533- {"scroll-timeline-axis", KeyType::SCROLL_TIMELINE_AXIS},
534- {"scroll-timeline-name", KeyType::SCROLL_TIMELINE_NAME},
535- {"scroll-timeline", KeyType::SCROLL_TIMELINE},
536- {"scrollbar-color", KeyType::SCROLLBAR_COLOR},
537- {"scrollbar-gutter", KeyType::SCROLLBAR_GUTTER},
538- {"scrollbar-width", KeyType::SCROLLBAR_WIDTH},
539- {"shape-image-threshold", KeyType::SHAPE_IMAGE_THRESHOLD},
540- {"shape-margin", KeyType::SHAPE_MARGIN},
541- {"shape-outside", KeyType::SHAPE_OUTSIDE},
542- {"shape-rendering", KeyType::SHAPE_RENDERING},
543- {"speak-as", KeyType::SPEAK_AS},
544- {"stop-color", KeyType::STOP_COLOR},
545- {"stop-opacity", KeyType::STOP_OPACITY},
546- {"stroke-dasharray", KeyType::STROKE_DASHARRAY},
547- {"stroke-dashoffset", KeyType::STROKE_DASHOFFSET},
548- {"stroke-linecap", KeyType::STROKE_LINECAP},
549- {"stroke-linejoin", KeyType::STROKE_LINEJOIN},
550- {"stroke-miterlimit", KeyType::STROKE_MITERLIMIT},
551- {"stroke-opacity", KeyType::STROKE_OPACITY},
552- {"stroke-width", KeyType::STROKE_WIDTH},
553- {"stroke", KeyType::STROKE},
554- {"tab-size", KeyType::TAB_SIZE},
555- {"table-layout", KeyType::TABLE_LAYOUT},
556- {"text-align-last", KeyType::TEXT_ALIGN_LAST},
557- {"text-align", KeyType::TEXT_ALIGN},
558- {"text-anchor", KeyType::TEXT_ANCHOR},
559- {"text-box-edge", KeyType::TEXT_BOX_EDGE},
560- {"text-box-trim", KeyType::TEXT_BOX_TRIM},
561- {"text-box", KeyType::TEXT_BOX},
562- {"text-combine-upright", KeyType::TEXT_COMBINE_UPRIGHT},
563- {"text-decoration-color", KeyType::TEXT_DECORATION_COLOR},
564- {"text-decoration-line", KeyType::TEXT_DECORATION_LINE},
565- {"text-decoration-skip-ink", KeyType::TEXT_DECORATION_SKIP_INK},
566- {"text-decoration-skip", KeyType::TEXT_DECORATION_SKIP},
567- {"text-decoration-style", KeyType::TEXT_DECORATION_STYLE},
568- {"text-decoration-thickness", KeyType::TEXT_DECORATION_THICKNESS},
569- {"text-decoration", KeyType::TEXT_DECORATION},
570- {"text-emphasis-color", KeyType::TEXT_EMPHASIS_COLOR},
571- {"text-emphasis-position", KeyType::TEXT_EMPHASIS_POSITION},
572- {"text-emphasis-style", KeyType::TEXT_EMPHASIS_STYLE},
573- {"text-emphasis", KeyType::TEXT_EMPHASIS},
574- {"text-indent", KeyType::TEXT_INDENT},
575- {"text-justify", KeyType::TEXT_JUSTIFY},
576- {"text-orientation", KeyType::TEXT_ORIENTATION},
577- {"text-overflow", KeyType::TEXT_OVERFLOW},
578- {"text-rendering", KeyType::TEXT_RENDERING},
579- {"text-shadow", KeyType::TEXT_SHADOW},
580- {"text-size-adjust", KeyType::TEXT_SIZE_ADJUST},
581- {"text-spacing-trim", KeyType::TEXT_SPACING_TRIM},
582- {"text-transform", KeyType::TEXT_TRANSFORM},
583- {"text-underline-offset", KeyType::TEXT_UNDERLINE_OFFSET},
584- {"text-underline-position", KeyType::TEXT_UNDERLINE_POSITION},
585- {"text-wrap-mode", KeyType::TEXT_WRAP_MODE},
586- {"text-wrap-style", KeyType::TEXT_WRAP_STYLE},
587- {"text-wrap", KeyType::TEXT_WRAP},
588- {"timeline-scope", KeyType::TIMELINE_SCOPE},
589- {"top", KeyType::TOP},
590- {"touch-action", KeyType::TOUCH_ACTION},
591- {"transform-box", KeyType::TRANSFORM_BOX},
592- {"transform-origin", KeyType::TRANSFORM_ORIGIN},
593- {"transform-style", KeyType::TRANSFORM_STYLE},
594- {"transform", KeyType::TRANSFORM},
595- {"transition-behavior", KeyType::TRANSITION_BEHAVIOR},
596- {"transition-delay", KeyType::TRANSITION_DELAY},
597- {"transition-duration", KeyType::TRANSITION_DURATION},
598- {"transition-property", KeyType::TRANSITION_PROPERTY},
599- {"transition-timing-function", KeyType::TRANSITION_TIMING_FUNCTION},
600- {"transition", KeyType::TRANSITION},
601- {"translate", KeyType::TRANSLATE},
602- {"unicode-bidi", KeyType::UNICODE_BIDI},
603- {"user-modify", KeyType::USER_MODIFY},
604- {"user-select", KeyType::USER_SELECT},
605- {"vector-effect", KeyType::VECTOR_EFFECT},
606- {"vertical-align", KeyType::VERTICAL_ALIGN},
607- {"view-timeline-axis", KeyType::VIEW_TIMELINE_AXIS},
608- {"view-timeline-inset", KeyType::VIEW_TIMELINE_INSET},
609- {"view-timeline-name", KeyType::VIEW_TIMELINE_NAME},
610- {"view-timeline", KeyType::VIEW_TIMELINE},
611- {"view-transition-class", KeyType::VIEW_TRANSITION_CLASS},
612- {"view-transition-name", KeyType::VIEW_TRANSITION_NAME},
613- {"visibility", KeyType::VISIBILITY},
614- {"white-space-collapse", KeyType::WHITE_SPACE_COLLAPSE},
615- {"white-space", KeyType::WHITE_SPACE},
616- {"widows", KeyType::WIDOWS},
617- {"width", KeyType::WIDTH},
618- {"will-change", KeyType::WILL_CHANGE},
619- {"word-break", KeyType::WORD_BREAK},
620- {"word-spacing", KeyType::WORD_SPACING},
621- {"writing-mode", KeyType::WRITING_MODE},
622- {"x", KeyType::X},
623- {"y", KeyType::Y},
624- {"z-index", KeyType::Z_INDEX},
625- {"zoom", KeyType::ZOOM}
626-};
627-
628-static const std::unordered_map<std::string_view, unsigned int> kColors {
629- {"black", 0x000000},
630- {"silver", 0xc0c0c0},
631- {"gray", 0x808080},
632- {"white", 0xffffff},
633- {"maroon", 0x800000},
634- {"red", 0xff0000},
635- {"purple", 0x800080},
636- {"fuchsia", 0xff00ff},
637- {"green", 0x008000},
638- {"lime", 0x00ff00},
639- {"olive", 0x808000},
640- {"yellow", 0xffff00},
641- {"navy", 0x000080},
642- {"blue", 0x0000ff},
643- {"teal", 0x008080},
644- {"aqua", 0x00ffff},
645- {"aliceblue", 0xf0f8ff},
646- {"antiquewhite", 0xfaebd7},
647- {"aqua", 0x00ffff},
648- {"aquamarine", 0x7fffd4},
649- {"azure", 0xf0ffff},
650- {"beige", 0xf5f5dc},
651- {"bisque", 0xffe4c4},
652- {"black", 0x000000},
653- {"blanchedalmond", 0xffebcd},
654- {"blue", 0x0000ff},
655- {"blueviolet", 0x8a2be2},
656- {"brown", 0xa52a2a},
657- {"burlywood", 0xdeb887},
658- {"cadetblue", 0x5f9ea0},
659- {"chartreuse", 0x7fff00},
660- {"chocolate", 0xd2691e},
661- {"coral", 0xff7f50},
662- {"cornflowerblue", 0x6495ed},
663- {"cornsilk", 0xfff8dc},
664- {"crimson", 0xdc143c},
665- {"cyan", 0x00ffff},
666- {"darkblue", 0x00008b},
667- {"darkcyan", 0x008b8b},
668- {"darkgoldenrod", 0xb8860b},
669- {"darkgray", 0xa9a9a9},
670- {"darkgreen", 0x006400},
671- {"darkgrey", 0xa9a9a9},
672- {"darkkhaki", 0xbdb76b},
673- {"darkmagenta", 0x8b008b},
674- {"darkolivegreen", 0x556b2f},
675- {"darkorange", 0xff8c00},
676- {"darkorchid", 0x9932cc},
677- {"darkred", 0x8b0000},
678- {"darksalmon", 0xe9967a},
679- {"darkseagreen", 0x8fbc8f},
680- {"darkslateblue", 0x483d8b},
681- {"darkslategray", 0x2f4f4f},
682- {"darkslategrey", 0x2f4f4f},
683- {"darkturquoise", 0x00ced1},
684- {"darkviolet", 0x9400d3},
685- {"deeppink", 0xff1493},
686- {"deepskyblue", 0x00bfff},
687- {"dimgray", 0x696969},
688- {"dimgrey", 0x696969},
689- {"dodgerblue", 0x1e90ff},
690- {"firebrick", 0xb22222},
691- {"floralwhite", 0xfffaf0},
692- {"forestgreen", 0x228b22},
693- {"fuchsia", 0xff00ff},
694- {"gainsboro", 0xdcdcdc},
695- {"ghostwhite", 0xf8f8ff},
696- {"gold", 0xffd700},
697- {"goldenrod", 0xdaa520},
698- {"gray", 0x808080},
699- {"green", 0x008000},
700- {"greenyellow", 0xadff2f},
701- {"grey", 0x808080},
702- {"honeydew", 0xf0fff0},
703- {"hotpink", 0xff69b4},
704- {"indianred", 0xcd5c5c},
705- {"indigo", 0x4b0082},
706- {"ivory", 0xfffff0},
707- {"khaki", 0xf0e68c},
708- {"lavender", 0xe6e6fa},
709- {"lavenderblush", 0xfff0f5},
710- {"lawngreen", 0x7cfc00},
711- {"lemonchiffon", 0xfffacd},
712- {"lightblue", 0xadd8e6},
713- {"lightcoral", 0xf08080},
714- {"lightcyan", 0xe0ffff},
715- {"lightgoldenrodyellow", 0xfafad2},
716- {"lightgray", 0xd3d3d3},
717- {"lightgreen", 0x90ee90},
718- {"lightgrey", 0xd3d3d3},
719- {"lightpink", 0xffb6c1},
720- {"lightsalmon", 0xffa07a},
721- {"lightseagreen", 0x20b2aa},
722- {"lightskyblue", 0x87cefa},
723- {"lightslategray", 0x778899},
724- {"lightslategrey", 0x778899},
725- {"lightsteelblue", 0xb0c4de},
726- {"lightyellow", 0xffffe0},
727- {"lime", 0x00ff00},
728- {"limegreen", 0x32cd32},
729- {"linen", 0xfaf0e6},
730- {"magenta", 0xff00ff},
731- {"maroon", 0x800000},
732- {"mediumaquamarine", 0x66cdaa},
733- {"mediumblue", 0x0000cd},
734- {"mediumorchid", 0xba55d3},
735- {"mediumpurple", 0x9370db},
736- {"mediumseagreen", 0x3cb371},
737- {"mediumslateblue", 0x7b68ee},
738- {"mediumspringgreen", 0x00fa9a},
739- {"mediumturquoise", 0x48d1cc},
740- {"mediumvioletred", 0xc71585},
741- {"midnightblue", 0x191970},
742- {"mintcream", 0xf5fffa},
743- {"mistyrose", 0xffe4e1},
744- {"moccasin", 0xffe4b5},
745- {"navajowhite", 0xffdead},
746- {"navy", 0x000080},
747- {"oldlace", 0xfdf5e6},
748- {"olive", 0x808000},
749- {"olivedrab", 0x6b8e23},
750- {"orange", 0xffa500},
751- {"orangered", 0xff4500},
752- {"orchid", 0xda70d6},
753- {"palegoldenrod", 0xeee8aa},
754- {"palegreen", 0x98fb98},
755- {"paleturquoise", 0xafeeee},
756- {"palevioletred", 0xdb7093},
757- {"papayawhip", 0xffefd5},
758- {"peachpuff", 0xffdab9},
759- {"peru", 0xcd853f},
760- {"pink", 0xffc0cb},
761- {"plum", 0xdda0dd},
762- {"powderblue", 0xb0e0e6},
763- {"purple", 0x800080},
764- {"rebeccapurple", 0x663399},
765- {"red", 0xff0000},
766- {"rosybrown", 0xbc8f8f},
767- {"royalblue", 0x4169e1},
768- {"saddlebrown", 0x8b4513},
769- {"salmon", 0xfa8072},
770- {"sandybrown", 0xf4a460},
771- {"seagreen", 0x2e8b57},
772- {"seashell", 0xfff5ee},
773- {"sienna", 0xa0522d},
774- {"silver", 0xc0c0c0},
775- {"skyblue", 0x87ceeb},
776- {"slateblue", 0x6a5acd},
777- {"slategray", 0x708090},
778- {"slategrey", 0x708090},
779- {"snow", 0xfffafa},
780- {"springgreen", 0x00ff7f},
781- {"steelblue", 0x4682b4},
782- {"tan", 0xd2b48c},
783- {"teal", 0x008080},
784- {"thistle", 0xd8bfd8},
785- {"tomato", 0xff6347},
786- {"transparent", 0x00000000},
787- {"turquoise", 0x40e0d0},
788- {"violet", 0xee82ee},
789- {"wheat", 0xf5deb3},
790- {"white", 0xffffff},
791- {"whitesmoke", 0xf5f5f5},
792- {"yellow", 0xffff00},
793- {"yellowgreen", 0x9acd32},
794-};
795-
796-struct SuffixParse {
797- std::string_view suffix;
798- UnitType type;
799- int trim; // chars to strip from the right
800-};
801-
802-static constexpr SuffixParse sufMatch[] = {
803- {"cqmin", UnitType::CQMIN, 5},
804- {"cqmax", UnitType::CQMAX, 5},
805- {"rcap", UnitType::RCAP, 4},
806- {"vmax", UnitType::VMAX, 4},
807- {"vmin", UnitType::VMIN, 4},
808- {"grad", UnitType::GRAD, 4},
809- {"turn", UnitType::TURN, 4},
810- {"cap", UnitType::CAP, 3},
811- {"rch", UnitType::RCH, 3},
812- {"rem", UnitType::REM, 3},
813- {"rex", UnitType::REX, 3},
814- {"ric", UnitType::RIC, 3},
815- {"rlh", UnitType::RLH, 3},
816- {"cqw", UnitType::CQW, 3},
817- {"cqh", UnitType::CQH, 3},
818- {"cqi", UnitType::CQI, 3},
819- {"cqb", UnitType::CQB, 3},
820- {"deg", UnitType::DEG, 3},
821- {"rad", UnitType::RAD, 3},
822- {"khz", UnitType::KHZ, 3},
823- {"kHz", UnitType::KHZ, 3},
824- {"Khz", UnitType::KHZ, 3},
825- {"KHz", UnitType::KHZ, 3},
826- {"KHZ", UnitType::KHZ, 3},
827- {"px", UnitType::PX, 2},
828- {"hz", UnitType::HZ, 2},
829- {"Hz", UnitType::HZ, 2},
830- {"HZ", UnitType::HZ, 2},
831- {"hZ", UnitType::HZ, 2},
832- {"ms", UnitType::MS, 2},
833- {"em", UnitType::EM, 2},
834- {"cm", UnitType::CM, 2},
835- {"ch", UnitType::CH, 2},
836- {"ex", UnitType::EX, 2},
837- {"ic", UnitType::IC, 2},
838- {"lh", UnitType::LH, 2},
839- {"vh", UnitType::VH, 2},
840- {"vw", UnitType::VW, 2},
841- {"vb", UnitType::VB, 2},
842- {"vi", UnitType::VI, 2},
843- {"mm", UnitType::MM, 2},
844- {"in", UnitType::IN, 2},
845- {"pc", UnitType::PC, 2},
846- {"pt", UnitType::PT, 2},
847- {"fr", UnitType::FRACTION,2},
848- {"%", UnitType::PERCENT,1},
849- {"q", UnitType::Q, 1},
850- {"s", UnitType::SECOND,1},
851-};
852-
853-
854-static const std::unordered_map<std::string_view, UnitType> kMatch{
855- {"+", UnitType::ADD},
856- {"-", UnitType::SUB},
857- {"*", UnitType::MULT},
858- {"/", UnitType::DIV},
859- {"==", UnitType::EQ},
860- {">", UnitType::GT},
861- {"<", UnitType::LT},
862- {">=", UnitType::GE},
863- {"<=", UnitType::LE},
864- {"and", UnitType::AND},
865- {"&&", UnitType::AND},
866- {"or", UnitType::OR},
867- {"||", UnitType::OR},
868- {"not", UnitType::NOT},
869- {"!=", UnitType::NOT},
870- {"only", UnitType::ONLY},
871- {"infinity", UnitType::INF},
872- {"-infinity", UnitType::NEGINF},
873- {"NaN", UnitType::NaN},
874- {"e", UnitType::E},
875- {"pi", UnitType::PI},
876- {"content-box", UnitType::CONTENT},
877- {"padding-box", UnitType::PADDING},
878- {"border-box", UnitType::BORDER},
879- {"margin-box", UnitType::MARGIN},
880- {"fill-box", UnitType::FILL},
881- {"stroke-box", UnitType::STROKE},
882- {"view-box", UnitType::VIEW},
883- {"space-between", UnitType::BETWEEN},
884- {"space-around", UnitType::AROUND},
885- {"space-evenly", UnitType::EVENLY},
886- {"stretch", UnitType::STRETCH},
887- {"normal", UnitType::NORMAL},
888- {"contents", UnitType::CONTENTS},
889- {"none", UnitType::NONE},
890- {"flow", UnitType::FLOW},
891- {"flow-root", UnitType::FLOW_ROOT},
892- {"table", UnitType::TABLE},
893- {"flex", UnitType::FLEX},
894- {"grid", UnitType::GRID},
895- {"ruby", UnitType::RUBY},
896- {"table-row-group", UnitType::TABLE_ROW_GROUP},
897- {"table-header-group", UnitType::TABLE_HEADER_GROUP},
898- {"table-footer-group", UnitType::TABLE_FOOTER_GROUP},
899- {"table-column-group", UnitType::TABLE_COLUMN_GROUP},
900- {"table-row", UnitType::TABLE_ROW},
901- {"table-cell", UnitType::TABLE_CELL},
902- {"table-column", UnitType::TABLE_COLUMN},
903- {"table-caption", UnitType::TABLE_CAPTION},
904- {"ruby-base", UnitType::RUBY_BASE},
905- {"ruby-text", UnitType::RUBY_TEXT},
906- {"ruby-base-container", UnitType::RUBY_BASE_CONTAINER},
907- {"ruby-text-container", UnitType::RUBY_TEXT_CONTAINER},
908- {"inline-block", UnitType::INLINE_BLOCK},
909- {"inline-table", UnitType::INLINE_TABLE},
910- {"inline-flex", UnitType::INLINE_FLEX},
911- {"inline-grid", UnitType::INLINE_GRID},
912- {"list-item", UnitType::LISTITEM},
913- {"block", UnitType::BLOCK},
914- {"inline", UnitType::INLINE},
915- {"run-in", UnitType::RUN_IN},
916- {"linear", UnitType::LINEAR},
917- {"ease", UnitType::EASE},
918- {"ease-in", UnitType::EASE_IN},
919- {"ease-out", UnitType::EASE_OUT},
920- {"ease-in-out", UnitType::EASE_IN_OUT},
921- {"step-start", UnitType::STEP_START},
922- {"step-end", UnitType::STEP_END},
923- {"jump-start", UnitType::JUMP_START},
924- {"jump-end", UnitType::JUMP_END},
925- {"jump-none", UnitType::JUMP_NONE},
926- {"jump-both", UnitType::JUMP_BOTH},
927- {"serif", UnitType::SERIF},
928- {"sans-serif", UnitType::SANS_SERIF},
929- {"monospace", UnitType::MONOSPACE},
930- {"cursive", UnitType::CURSIVE},
931- {"fantasy", UnitType::FANTASY},
932- {"system-ui", UnitType::SYSTEM_UI},
933- {"ui-serif", UnitType::UI_SERIF},
934- {"ui-sans-serif", UnitType::UI_SANS_SERIF},
935- {"ui-monospace", UnitType::UI_MONOSPACE},
936- {"ui-rounded", UnitType::UI_ROUNDED},
937- {"math", UnitType::MATH},
938- {"fangsong", UnitType::FANGSONG},
939- {"top", UnitType::TOP},
940- {"left", UnitType::LEFT},
941- {"bottom", UnitType::BOTTOM},
942- {"right", UnitType::RIGHT},
943- {"center", UnitType::CENTER},
944- {"start", UnitType::START},
945- {"end", UnitType::END},
946- {"inline-start", UnitType::INLINE_START},
947- {"inline-end", UnitType::INLINE_END},
948- {"block-start", UnitType::BLOCK_START},
949- {"block-end", UnitType::BLOCK_END},
950- {"self-start", UnitType::SELF_START},
951- {"self-end", UnitType::SELF_END},
952- {"flex-start", UnitType::FLEX_START},
953- {"flex-end", UnitType::FLEX_END},
954- {"circle", UnitType::CIRCLE},
955- {"ellipse", UnitType::ELLIPSE},
956- {"shorterhue", UnitType::SHORTER_HUE},
957- {"longerhue", UnitType::LONGER_HUE},
958- {"increasinghue", UnitType::INCREASING_HUE},
959- {"decreasinghue", UnitType::DECREASING_HUE},
960- {"dotted", UnitType::DOTTED},
961- {"dashed", UnitType::DASHED},
962- {"solid", UnitType::SOLID},
963- {"double", UnitType::DOUBLE},
964- {"groove", UnitType::GROOVE},
965- {"ridge", UnitType::RIDGE},
966- {"inset", UnitType::INSET},
967- {"outset", UnitType::OUTSET},
968- {"baseline", UnitType::FIRST_BASELINE},
969- {"firstbaseline", UnitType::FIRST_BASELINE},
970- {"lastbaseline", UnitType::LAST_BASELINE},
971- {"safe", UnitType::SAFE},
972- {"unsafe", UnitType::UNSAFE},
973- {"visible", UnitType::VISIBLE},
974- {"clip", UnitType::CLIP},
975- {"scroll", UnitType::SCROLL},
976- {"inherit", UnitType::INHERIT},
977- {"initial", UnitType::INITIAL},
978- {"revert", UnitType::REVERT},
979- {"revert-layer", UnitType::REVERT_LAYER},
980- {"unset", UnitType::UNSET},
981- {"nearest", UnitType::NEAREST},
982- {"up", UnitType::UP},
983- {"down", UnitType::DOWN},
984- {"to-zero", UnitType::TO_ZERO},
985-};
986-
987-static const std::unordered_map<std::string_view, UnitType> kFunc{
988- {"calc", UnitType::CALC},
989- {"min", UnitType::MIN},
990- {"max", UnitType::MAX},
991- {"clamp", UnitType::CLAMP},
992- {"round", UnitType::ROUND},
993- {"mod", UnitType::MOD},
994- {"progress", UnitType::PROGRESS},
995- {"rem", UnitType::REMD},
996- {"pow", UnitType::POW},
997- {"sqrt", UnitType::SQRT},
998- {"set", UnitType::SET},
999- {"let", UnitType::LET},
1000- {"hypot", UnitType::HYPOT},
1001- {"log", UnitType::LOG},
1002- {"exp", UnitType::EXP},
1003- {"abs", UnitType::ABS},
1004- {"sin", UnitType::SIN},
1005- {"cos", UnitType::COS},
1006- {"tan", UnitType::TAN},
1007- {"asin", UnitType::ASIN},
1008- {"acos", UnitType::ACOS},
1009- {"atan", UnitType::ATAN},
1010- {"atan2", UnitType::ATAN2},
1011- {"sign", UnitType::SIGN},
1012- {"var", UnitType::VAR_FUNC},
1013- {"rgb", UnitType::RGB},
1014- {"rgba", UnitType::RGBA},
1015- {"hsl", UnitType::HSL},
1016- {"linear", UnitType::LINEAR_EASING_FUNCTION},
1017- {"cubic-bezier", UnitType::CUBIC_BEZIER_FUNCTION},
1018- {"steps", UnitType::STEPS_FUNCTION},
1019- {"blur", UnitType::BLUR},
1020- {"brightness", UnitType::BRIGHTNESS},
1021- {"contrast", UnitType::CONTRAST},
1022- {"drop-shadow", UnitType::DROP_SHADOW},
1023- {"grayscale", UnitType::GRAYSCALE},
1024- {"hue-rotate", UnitType::HUE_ROTATE},
1025- {"invert", UnitType::INVERT},
1026- {"opacity", UnitType::OPACITY},
1027- {"sepia", UnitType::SEPIA},
1028- {"saturate", UnitType::SATURATE},
1029- {"image", UnitType::IMAGE},
1030- {"image-set", UnitType::IMAGE_SET},
1031- {"cross-fade", UnitType::CROSS_FADE},
1032- {"element", UnitType::ELEMENT},
1033- {"gradient", UnitType::GRADIENT},
1034- {"matrix", UnitType::MATRIX},
1035- {"matrix3d", UnitType::MATRIX3D},
1036- {"perspective", UnitType::PERSPECTIVE},
1037- {"rotate", UnitType::ROTATE},
1038- {"rotate3d", UnitType::ROTATE3D},
1039- {"rotateX", UnitType::ROTATEX},
1040- {"rotateY", UnitType::ROTATEY},
1041- {"rotateZ", UnitType::ROTATEZ},
1042- {"scale", UnitType::SCALE},
1043- {"scale3d", UnitType::SCALE3D},
1044- {"scaleX", UnitType::SCALEX},
1045- {"scaleY", UnitType::SCALEY},
1046- {"scaleZ", UnitType::SCALEZ},
1047- {"translate", UnitType::TRANSLATE},
1048- {"translate3d", UnitType::TRANSLATE3D},
1049- {"translateX", UnitType::TRANSLATEX},
1050- {"translateY", UnitType::TRANSLATEY},
1051- {"translateZ", UnitType::TRANSLATEZ},
1052- {"skew", UnitType::SKEW},
1053- {"skewX", UnitType::SKEWX},
1054- {"skewY", UnitType::SKEWY},
1055- {"url", UnitType::URL},
1056- {"attr", UnitType::ATTR},
1057- {"type", UnitType::TYPE},
1058- {"env", UnitType::ENV},
1059- {"if", UnitType::IF},
1060- {"var", UnitType::VAR},
1061- {"", UnitType::GROUP}
1062-};
1063-
1064-static const std::unordered_map<std::string_view, float> kAbsSize{
1065- {"xx-small",0.6f}, {"x-small",0.75f}, {"small",0.89f}, {"medium",1.0f},
1066- {"large",1.2f}, {"x-large",1.5f}, {"xx-large",2.0f}, {"xxx-large",3.0f}
1067-};
1068-
1069-/*
1070- Parses a string into Unit's and stores variables & strings into the Style object
1071-
1072-*/
1073-
1074-std::vector<Unit> getUnit(std::string value, SymbolTable* externalTable = nullptr) {
1075- SymbolTable localTable;
1076- SymbolTable& table = (externalTable != nullptr) ? *externalTable : localTable;
1077-
1078- std::vector<Unit> units;
1079-
1080- std::string buffer = "";
1081- std::string str_buffer = "";
1082- int parenDepth = 0;
1083- bool inQuotes = false;
1084- // Needs to not be empty but can't be a quote
1085- char quoteType = 'a';
1086- bool escaped = false;
1087-
1088- for (size_t i = 0; i < value.length(); i++) {
1089- char v = value[i];
1090- if (v == '\\' && !escaped) escaped = true;
1091- if (!escaped && (v == '"' || v == '\'') && parenDepth == 0) {
1092- if (inQuotes && v == quoteType) {
1093- for (size_t j = 0; j < str_buffer.length(); j++) {
1094- Unit unit{};
1095- unit.type = UnitType::STRING;
1096- unit.value.CHAR = str_buffer[j];
1097- units.push_back(unit);
1098- }
1099-
1100- str_buffer.clear();
1101-
1102- Unit unit{};
1103- unit.type = UnitType::STRING_TERM;
1104- unit.value.INT = str_buffer.length();
1105- units.push_back(unit);
1106-
1107- inQuotes = false;
1108- } else if (!inQuotes) {
1109- quoteType = v;
1110- inQuotes = true;
1111- }
1112- continue;
1113- }
1114-
1115- if (!inQuotes) {
1116- if (v == '(') parenDepth++;
1117- else if (v == ')') parenDepth--;
1118- }
1119-
1120- if (parenDepth > 0) {
1121- buffer.push_back(v);
1122- continue;
1123- } else if (v == ')') {
1124- /*
1125- Function handling
1126- */
1127- // We are at the end of the parentheseses and we need to pass it for more parsing
1128- std::string name;
1129- bool nameset = false;
1130- std::string value;
1131-
1132- for (size_t j = 0; j < buffer.size(); j++) {
1133- if (nameset) {
1134- value.push_back(buffer[j]);
1135- } else {
1136- if (buffer[j] == '(') nameset = true;
1137- else name.push_back(buffer[j]);
1138- }
1139- }
1140-
1141- std::vector<Unit> children = getUnit(value, &table);
1142-
1143- Unit unit;
1144-
1145- if (auto it = kFunc.find(name); it != kFunc.end()) {
1146- unit.type = it->second;
1147- } else {
1148- unit.type = UnitType::FUNC;
1149- }
1150-
1151- // The value of the function is the child count
1152- unit.value.INT = children.size();
1153-
1154- units.push_back(unit);
1155- units.insert(units.end(), children.begin(), children.end());
1156- // Add a end value for the function
1157-
1158- buffer.clear();
1159- } else if ((!inQuotes && (v == ',' || std::isspace(v))) || i >= value.length()-1) {
1160- if (v != ',' && !std::isspace(v)) buffer.push_back(v);
1161-
1162- Unit unit;
1163-
1164- // Split by spaces into parts
1165-
1166- if (auto it = kMatch.find(buffer); it != kMatch.end()) {
1167- /*
1168- Keyword Matching
1169- */
1170- unit.type = it->second;
1171- // the value is not used here
1172- } else if (auto it = kColors.find(buffer); it != kColors.end()) {
1173- /*
1174- Color Matching
1175- */
1176- unit.type = UnitType::HEX;
1177- unit.value.UINT = it->second;
1178- } else {
1179- bool found = false;
1180- for (const auto& [suffix, type, trim] : sufMatch) {
1181- if (buffer.ends_with(suffix)) {
1182- found = true;
1183- try {
1184- unit.value.FLOAT = std::stof(std::string(buffer.substr(0, buffer.size() - trim)));
1185- } catch (...) {
1186- unit.value.FLOAT = 0.0f;
1187- }
1188-
1189- unit.type = type;
1190- break;
1191- }
1192- }
1193-
1194- if (!found) {
1195- if (buffer.starts_with("#") && buffer.length() > 1) {
1196- /*
1197- # Prefix for HEX codes
1198- */
1199- unit.type = UnitType::HEX;
1200- unit.value.UINT = std::stoul(buffer.substr(1), nullptr, 16);
1201- } else if (auto it = kAbsSize.find(buffer); it != kAbsSize.end()) {
1202- /*
1203- Absolute size matching
1204- */
1205- unit.type = UnitType::EM;
1206- unit.value.FLOAT = it->second;
1207- } else if (buffer == "true") {
1208- unit.type = UnitType::BOOL;
1209- unit.value.BOOL = true;
1210- } else if (buffer == "true") {
1211- unit.type = UnitType::BOOL;
1212- unit.value.BOOL = false;
1213- } else {
1214- // Maybe its a number?
1215- try {
1216- unit.value.FLOAT = std::stof(buffer);
1217- unit.type = UnitType::NUMBER;
1218- } catch (...) {
1219- // If we are here it is not a known parsable word, this could be a typo
1220- // or a keyword like with the attr(size px) function. Here px would be
1221- // parsed but not size.
1222- if (!buffer.empty() && buffer.find_first_not_of(' ') != std::string::npos) {
1223- unit.type = UnitType::VAR;
1224- unit.value.INT = table.get(buffer);
1225- } else {
1226- continue;
1227- }
1228- }
1229- }
1230- }
1231- }
1232-
1233- units.push_back(unit);
1234- buffer.clear();
1235- } else if (inQuotes) {
1236- str_buffer.push_back(v);
1237- } else {
1238- buffer.push_back(v);
1239- }
1240-
1241- escaped = false;
1242- if (v == '\\') escaped = true;
1243- }
1244-
1245- return units;
1246-}
1247-
1248-Style parseCSS(std::istream& inputStream) {
1249- // nowhitespace: value(can have whitespace); = property
1250- // a selector name is anything before a { up to a ; or a }
1251- std::vector<Style*> stack;
1252- Style root{};
1253- Style* current = &root;
1254-
1255- // how to handle @import
1256-
1257- std::string buffer;
1258-
1259- bool incomment = false;
1260-
1261-
1262- SymbolTable table;
1263-
1264- char ch;
1265- while (inputStream.get(ch)) {
1266- if (ch == '*' && inputStream.peek() == '/') {
1267- incomment = false;
1268- // Skip ahead to the next letter so we don't capture the trailing /
1269- inputStream.get(ch);
1270- continue;
1271- }
1272- if (ch == '/' && inputStream.peek() == '*') {
1273- incomment = true;
1274- }
1275-
1276- if (incomment) {
1277- continue;
1278- }
1279-
1280- if (ch == '{') {
1281- for (size_t i = buffer.length()-1; i >= 0; i--) {
1282- if (std::isspace(buffer[i])) {
1283- buffer.pop_back();
1284- } else {
1285- break;
1286- }
1287- }
1288-
1289- // Parse the selector into its parts
1290- std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
1291-
1292- if (current->selector.size() > 0) {
1293- // To be able to handle a substitution with a parent that has h1, h2
1294- // we need to rebuild the selector so we can add new copies
1295- std::vector<std::vector<std::string>> subd;
1296-
1297- // Look for any & if its a style and replace it with the parsed parent selector
1298- for (size_t i = 0; i < parts.size(); i++) {
1299- bool hasAmp = false;
1300- for (size_t e = 0; e < parts[i].size(); e++) {
1301- if (parts[i][e] == "&") {
1302- hasAmp = true;
1303- break;
1304- }
1305- }
1306-
1307- if (hasAmp) {
1308- // If it contains a amp then we need replace the amp with each parent selector
1309- // Inject each part of the parent
1310- // Parent [[h1],[h2]]
1311- // Child: [[& .class, &, &]]
1312- // Result: [[h1 .class, h1, h1]]
1313- // [[h2 .class, h2, h2]]
1314- for (size_t e = 0; e < current->selector.size(); e++) {
1315- std::vector<std::string> temp;
1316- for (size_t f = 0; f < parts[i].size(); f++) {
1317- if (parts[i][f] == "&") {
1318- for (auto p : current->selector[e]) {
1319- temp.push_back(p);
1320- }
1321- } else {
1322- temp.push_back(parts[i][f]);
1323- }
1324- }
1325- subd.push_back(temp);
1326- }
1327- } else {
1328- // If there's nothing to replace just add to back
1329- subd.push_back(parts[i]);
1330- }
1331- }
1332-
1333- parts = subd;
1334- }
1335-
1336- stack.push_back(current);
1337-
1338- Style newSheet{};
1339- newSheet.selector = parts;
1340- current->addChild(newSheet);
1341-
1342- current = ¤t->children.back();
1343-
1344- buffer.clear();
1345- } else if (ch == '}') {
1346-
1347- if (!stack.empty()) {
1348- current = stack.back();
1349- stack.pop_back();
1350- }
1351-
1352- buffer.clear();
1353- } else if (ch == ';') {
1354- if (buffer[0] == '@') {
1355- // Single line at-rule
1356- Style inlineRule;
1357- std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
1358- inlineRule.selector = parts;
1359-
1360- if (parts[0][0] == "@import") {
1361- inlineRule.selector = parts;
1362-
1363- if (parts[0].size() > 3) {
1364- // See if the last word ends in )
1365- // if not then its the name of the layer
1366- if (parts[0].back().back() != ')') {
1367- inlineRule.name = parts[0].back();
1368- }
1369- }
1370-
1371- } else if (parts[0][0] == "@layer") {
1372- // ISSUE: need to add specificity
1373-
1374- }
1375-
1376- current->addChild(inlineRule);
1377-
1378- } else {
1379- // end of a style property
1380- std::string key;
1381- std::string value;
1382- bool keyFound = false;
1383- bool firstValue = false;
1384- for (size_t i = 0; i < buffer.length(); i++) {
1385- char c = buffer[i];
1386- if (!keyFound && c == ':') {
1387- keyFound = true;
1388- } else if (!std::isspace(c) && !keyFound) {
1389- key += c;
1390- } else if (!firstValue && keyFound && !std::isspace(c)) {
1391- firstValue = true;
1392- value += c;
1393- } else if (keyFound && firstValue && !(std::isspace(c) && i < buffer.length()-1 && std::isspace(buffer[i+1]))) {
1394- // if the key is found and the character isn't a ':'
1395- // also (if c is a space and the next c will be a space)
1396- // this is to auto trim duplicate spaces from the value
1397- value += c;
1398- }
1399- }
1400-
1401- if (key.length() > 2 && key[0] == '-' && key[1] == '-') {
1402- current->variables.set(key, getUnit(value, &table));
1403- } else {
1404- KeyType keyENUM;
1405-
1406- if (auto it = keySearch.find(key); it != keySearch.end()) {
1407- keyENUM = it->second;
1408- } else {
1409- std::cout << "Invalid property name: " << key << std::endl;
1410- }
1411- current->properties[keyENUM] = getUnit(value, &table);
1412- }
1413- }
1414- buffer.clear();
1415- } else {
1416- buffer.push_back(ch);
1417- }
1418- }
1419-
1420- return root;
1421-}
1422-
1423-std::string get_working_path() {
1424- char temp [ PATH_MAX ];
1425-
1426- if ( getcwd(temp, PATH_MAX) != 0)
1427- return std::string ( temp );
1428-
1429- int error = errno;
1430-
1431- switch ( error ) {
1432- // EINVAL can't happen - size argument > 0
1433-
1434- // PATH_MAX includes the terminating nul,
1435- // so ERANGE should not be returned
1436-
1437- case EACCES:
1438- throw std::runtime_error("Access denied");
1439-
1440- case ENOMEM:
1441- // I'm not sure whether this can happen or not
1442- throw std::runtime_error("Insufficient storage");
1443-
1444- default: {
1445- std::ostringstream str;
1446- str << "Unrecognised error" << error;
1447- throw std::runtime_error(str.str());
1448- }
1449- }
1450-}
1451-
1452-std::string pathJoin(const std::string& p1, const std::string& p2) {
1453- char sep = '/';
1454- std::string tmp = p1;
1455-
1456-#ifdef _WIN32
1457- sep = '\\';
1458-#endif
1459-
1460- // Add separator if it is not included in the first path:
1461- if (p1[p1.length() - 1] != sep) {
1462- tmp += sep;
1463- return tmp + p2;
1464- } else {
1465- return p1 + p2;
1466- }
1467-}
1468-
1469-struct ParsedDocument {
1470- Node document;
1471- Style CSS;
1472-};
1473-
1474-ParsedDocument parseDocument(std::istream& inputStream) {
1475- Node root;
1476- root.setTagName("root");
1477-
1478- Node* currentNode = &root;
1479-
1480- bool inTag = false;
1481- bool escaped = false;
1482- bool inQuote = false;
1483- bool inComment = false;
1484- bool waitToClose = false;
1485- char quoteType = '"';
1486-
1487- std::string token;
1488-
1489- // CSS stuff
1490- std::vector<std::string> cssLinks;
1491- std::vector<std::string> cssTags;
1492-
1493- char current;
1494- while (inputStream.get(current)) {
1495- // Finds the --> and removes it then resets inComment
1496- if (inComment) {
1497- // added the peek to prevent hitting on every -
1498- if (current == '-' && inputStream.peek() == '-') {
1499- char a,b;
1500- // load the next two
1501- if (inputStream.get(a) && inputStream.get(b)) {
1502- // We know a == -
1503- if (b == '>') {
1504- // Close the comment
1505- inComment = false;
1506- }
1507- }
1508-
1509- if (!inComment) {
1510- // we don't put anything back and that puts us where we need to be
1511- continue;
1512- } else {
1513- // Not the end
1514- inputStream.putback(b);
1515- inputStream.putback(a);
1516- }
1517- }
1518- continue;
1519- }
1520-
1521- std::string tagName = currentNode->getTagName();
1522- if (!waitToClose && (
1523- tagName == "style" ||
1524- tagName == "script" ||
1525- tagName == "textarea"
1526- ) && current == '<' && inputStream.peek() == '/' ) {
1527- // If its the starting of a closing tag and we are inside of a special tag
1528- // we need to see if the upcoming closing tag is the correct closing tag
1529- // if it is then we put the read ahead back and waitToClose. This will let normal parsing
1530- // continue
1531- const size_t readTo = tagName.length()+2;
1532- std::string buffer(readTo, '\0');
1533-
1534- inputStream.read(&buffer[0], readTo);
1535-
1536- if (buffer == "/"+tagName+">") {
1537- waitToClose = true;
1538- } else {
1539- token += current;
1540- }
1541-
1542- for (int i = readTo-1; i>= 0; i--) {
1543- inputStream.putback(buffer[i]);
1544- }
1545- if (!waitToClose) {
1546- continue;
1547- }
1548- } else if (!waitToClose && (
1549- tagName == "style" ||
1550- tagName == "script" ||
1551- tagName == "textarea"
1552- )) {
1553- token += current;
1554- continue;
1555- }
1556-
1557- if (inTag) {
1558- if ((current == '"' || current == '\'') && !escaped) {
1559- if (inQuote && current == quoteType) {
1560- inQuote = false;
1561- } else if (!inQuote) {
1562- inQuote = true;
1563- quoteType = current;
1564- }
1565- }
1566-
1567- if (current == '>' && !inQuote && !escaped) {
1568- inTag = false;
1569- waitToClose = false;
1570- // Even if the next tag is next still add a text tag as we can just check if its empty and remove it
1571- // this check would still have to be done either way so we aren't wasting anything
1572- if (token.length() > 0) {
1573- bool empty = true;
1574- bool closingTag = false;
1575- for (size_t i = 0; i < token.length(); i++) {
1576- auto c = token[i];
1577- if (std::isspace(c)) {
1578- continue;
1579- } else if (c == '/') {
1580- closingTag = true;
1581- } else {
1582- empty = false;
1583- break;
1584- }
1585- }
1586-
1587- bool selfClosing = false;
1588- int selfClosingPosition = token.length()-1;
1589- if (!closingTag) {
1590- for (int i = token.length()-1; i >= 0; i--) {
1591- auto c = token[i];
1592- if (std::isspace(c)) {
1593- continue;
1594- } else if (c == '/') {
1595- selfClosingPosition = i;
1596- selfClosing = true;
1597- break;
1598- } else {
1599- break;
1600- }
1601- }
1602- }
1603-
1604- if (!empty) {
1605- if (selfClosing) {
1606- //Create element and don't jump inside
1607- // Use node instead of currentNode because we do not need to jump into the created element
1608- auto attrs = parseAttributes(token.substr(0, selfClosingPosition));
1609- auto node = currentNode->createElement(attrs["tagName"]);
1610- for (auto const& pair : attrs) {
1611- // All attributes are stored as strings so we can just throw them in
1612- node->setAttribute(pair.first, pair.second);
1613- }
1614- if (attrs["tagName"] == "link" && attrs["rel"] == "stylesheet") {
1615- cssLinks.push_back(node->getAttribute("href"));
1616- } else if (attrs["tagName"] == "style") {
1617- cssTags.push_back(node->getAttribute("innerText"));
1618- }
1619- } else if (closingTag) {
1620- // Checksum and tree move
1621- std::string tagName = "";
1622- for (auto t : token) {
1623- if (!std::isspace(t) && t != '/') {
1624- tagName += t;
1625- } else if (t == '/') {
1626- // For closing tags we just want the name
1627- continue;
1628- } else if (tagName.length() > 0) {
1629- break;
1630- }
1631- }
1632-
1633- if (currentNode->getTagName() == tagName) {
1634- if (tagName == "link" && currentNode->getAttribute("rel") == "stylesheet") {
1635- cssLinks.push_back(currentNode->getAttribute("href"));
1636- } else if (tagName == "style") {
1637- cssTags.push_back(currentNode->children[0].getAttribute("innerText"));
1638- }
1639-
1640- currentNode = currentNode->parent;
1641- } else {
1642- std::cerr << "malformed html: closing tag (</" << tagName << ">) found for <" << currentNode->getTagName() << ">" << std::endl;
1643- }
1644- } else {
1645- // Create a element and jump inside
1646- auto attrs = parseAttributes(token);
1647- // Don't add elements like <!DOCTYPE>
1648- if (attrs["tagName"][0] != '!') {
1649- currentNode = currentNode->createElement(attrs["tagName"]);
1650- for (auto const& pair : attrs) {
1651- // All attributes are stored as strings so we can just throw them in
1652- currentNode->setAttribute(pair.first, pair.second);
1653- }
1654- }
1655-
1656- }
1657- }
1658- }
1659-
1660- token = "";
1661- continue;
1662- }
1663- } else if (!escaped && current == '<') {
1664- // if the next character is a !
1665- if (inputStream.peek() == '!') {
1666- char a,b,c;
1667- // load the next three characters (includes !)
1668- if (inputStream.get(a) && inputStream.get(b) && inputStream.get(c)) {
1669- // We know a == !
1670- if (b == '-' && c == '-') {
1671- inComment = true;
1672- }
1673- }
1674-
1675- if (inComment) {
1676- continue;
1677- } else {
1678- // Not a comment add all back
1679- inputStream.putback(c);
1680- inputStream.putback(b);
1681- inputStream.putback(a);
1682- }
1683- }
1684- inTag = true;
1685-
1686- // Here's where you actually make the text node and above the real nodes
1687- // can also prob make the vector of tokens a single variable
1688- // it really just needs to be a data string bc we know the type based on inTag
1689-
1690-
1691- bool hasText = false;
1692- for (auto t : token) {
1693- if (!std::isspace(t)) {
1694- hasText = true;
1695- break;
1696- }
1697- }
1698-
1699- // TODO: Add a vector that stores inner text and when elements start to close out pop them but add all to their innerText
1700- // | Will need something similar for innerHTML
1701- if (hasText) {
1702- auto node = currentNode->createElement("text");
1703- node->setAttribute("innerText", token);
1704- }
1705-
1706-
1707- token = "";
1708- continue;
1709- }
1710-
1711- escaped = false;
1712-
1713- if (current == '\\') { //'
1714- escaped = true;
1715- continue;
1716- }
1717-
1718- token += current;
1719- }
1720-
1721- ParsedDocument doc;
1722- doc.document = root;
1723-
1724- Style style;
1725-
1726- std::string workingPath = get_working_path();
1727-
1728- for (size_t i = 0; i < cssLinks.size(); i++) {
1729- std::string link = cssLinks[i];
1730-
1731- std::ifstream file(pathJoin(workingPath, link));
1732-
1733- if (!file.is_open()) {
1734- std::cerr << "Failed to open file!" << std::endl;
1735- } else {
1736- Style s = parseCSS(file);
1737-
1738- for (size_t j = 0; j < s.children.size(); j++) {
1739- style.addChild(s.children[j]);
1740- }
1741- }
1742- file.close();
1743- }
1744-
1745- for (size_t i = 0; i < cssTags.size(); i++) {
1746- std::string tag = cssTags[i];
1747-
1748- std::istringstream iss(tag);
1749- Style s = parseCSS(iss);
1750-
1751- for (size_t j = 0; j < s.children.size(); j++) {
1752- style.addChild(s.children[j]);
1753- }
1754- }
1755-
1756- doc.CSS = style;
1757-
1758- return doc;
1759-}
1760diff --git a/include/grim.h b/include/grim.h
1761index 3f6f5db..45d25bb 100755
1762--- a/include/grim.h
1763+++ b/include/grim.h
1764@@ -90,7 +90,7 @@ enum class UnitType : short {
1765 NEAREST, UP, DOWN, TO_ZERO,
1766
1767 // Keyword
1768- PRINT, SCREEN, TOKEN, NO_SUPPORT, IMAGE, STRING, BOOL, VAR, STRING_TERM, NONOP,
1769+ PRINT, SCREEN, TOKEN, NO_SUPPORT, IMAGE, STRING, BOOL, VAR, STRING_TERM, NONOP, ELSE,
1770
1771 FUNC_START,
1772 // General Functions
1773@@ -98,6 +98,7 @@ enum class UnitType : short {
1774 HYPOT, LOG, EXP, ABS, SIGN, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, VAR_FUNC,
1775 BLUR, BRIGHTNESS, CONTRAST, DROP_SHADOW, GRAYSCALE, HUE_ROTATE, INVERT,
1776 OPACITY, SEPIA, SATURATE, ATTR, TYPE, ENV, IF, FUNC, LET, RETURN, SET,
1777+ LIST,
1778
1779 // Easing Functions
1780 EASING_FUNCTION, LINEAR_EASING_FUNCTION, LINEAR, EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUBIC_BEZIER_FUNCTION,
1781diff --git a/playground/syntax.wr b/playground/syntax.wr
1782index f0648a9..7c6a2fe 100644
1783--- a/playground/syntax.wr
1784+++ b/playground/syntax.wr
1785@@ -1,9 +1,9 @@
1786 Context -> width -> screen -> etc
1787
1788 (
1789- let(x, (1 + 1)),
1790- let(x, x + 1),
1791- print(x),
1792+ let(x (1 + 1))
1793+ set(x (x + 1))
1794+ print(x)
1795
1796 func(uppercase, (str), (
1797 map(str, func((e),
1798@@ -12,9 +12,10 @@ Context -> width -> screen -> etc
1799 )
1800 )),
1801
1802- let(uppercase, func((str),
1803- map(str, func((e),
1804- e + 20
1805+ let(uppercase, func((str) (
1806+ map(str, func((e)
1807+ set(e (e + 20))
1808+ )
1809 )
1810 )
1811 )
1812diff --git a/playground/unitvalue.cc b/playground/unitvalue.cc
1813index b0a0909..bab6d4a 100644
1814--- a/playground/unitvalue.cc
1815+++ b/playground/unitvalue.cc
1816@@ -55,10 +55,7 @@ int main() {
1817 m.push_back(sym.get("height"),{UnitType::NUMBER, {.FLOAT = 700.0f}});
1818 m.push_back(sym.get("em"),{UnitType::NUMBER, {.FLOAT= 16.0f}});
1819
1820- //std::vector<Unit> units = getUnit("(let(x, 10px), set(x, (x + 1)), min(5, x))", &sym);
1821- std::vector<Unit> units = getUnit("let(x 10px) set(x (x + 100)) min(5 x)", &sym);
1822- //std::vector<Unit> units = getUnit("true and false", &sym);
1823-
1824+ std::vector<Unit> units = getUnit("if((1 > 1): 10px; else: 11vw;)", &sym);
1825
1826 Unit u = UnitValue(m, units, 0, units.size());
1827
1828diff --git a/src/grim.cc b/src/grim.cc
1829index cc02744..0ea2d69 100755
1830--- a/src/grim.cc
1831+++ b/src/grim.cc
1832@@ -877,7 +877,7 @@ std::unordered_map<std::string, Media> MediaLookup {
1833 bool executeQuery(Window* w, std::string p) {
1834 Context c;
1835 c.id = window->symbol_table.get("all");
1836- c.value.type = UnitType::BOOL;
1837+ c.type = UnitType::BOOL;
1838 c.value.BOOL = w->getMedia() == Media::All;
1839 c.previous = nullptr;
1840
1841@@ -1497,6 +1497,44 @@ Unit UnitValue(Memory& m, std::vector<Unit>& units, size_t start, size_t end) {
1842 }
1843
1844 i += unit.value.INT;
1845+ break;
1846+ }
1847+ case UnitType::PRINT: {
1848+ Unit u = UnitValue(m, units, i+1, i+1+unit.value.INT);
1849+ std::cout << "> " << u.value.FLOAT << std::endl;
1850+ iv = u;
1851+ i += unit.value.INT;
1852+ break;
1853+ }
1854+ case UnitType::IF: {
1855+ Range args[4]; // condition trueval else falseval
1856+ int found = 0;
1857+ size_t start = i + 1;
1858+ size_t end = i + 1 + unit.value.INT;
1859+
1860+ while (start < end) {
1861+ args[found++] = getNextUnit(units, start, end);
1862+ }
1863+
1864+ bool condition = UnitValue(m, units, args[0].start, args[0].end).value.BOOL;
1865+
1866+ if (condition) {
1867+ iv = UnitValue(m, units, args[1].start, args[1].end);
1868+ } else {
1869+ UnitType u = units[args[2].start].type;
1870+ if (u == UnitType::ELSE) {
1871+ iv = UnitValue(m, units, args[3].start, args[3].end);
1872+ } else {
1873+ iv = UnitValue(m, units, args[2].start, args[2].end);
1874+ }
1875+ }
1876+
1877+
1878+ i += unit.value.INT;
1879+ break;
1880+ }
1881+ case UnitType::LIST: {
1882+
1883 }
1884 }
1885
1886diff --git a/src/parser.cc b/src/parser.cc
1887index c67be3a..b92c0b3 100755
1888--- a/src/parser.cc
1889+++ b/src/parser.cc
1890@@ -857,6 +857,7 @@ static const std::unordered_map<std::string_view, UnitType> kMatch{
1891 {"not", UnitType::NOT},
1892 {"!=", UnitType::NOT},
1893 {"only", UnitType::ONLY},
1894+ {"else", UnitType::ELSE},
1895 {"infinity", UnitType::INF},
1896 {"-infinity", UnitType::NEGINF},
1897 {"NaN", UnitType::NaN},
1898@@ -1047,6 +1048,8 @@ static const std::unordered_map<std::string_view, UnitType> kFunc{
1899 {"env", UnitType::ENV},
1900 {"if", UnitType::IF},
1901 {"var", UnitType::VAR},
1902+ {"print", UnitType::PRINT},
1903+ {"list", UnitType::LIST},
1904 {"", UnitType::GROUP}
1905 };
1906
1907@@ -1104,6 +1107,8 @@ std::vector<Unit> getUnit(std::string value, SymbolTable* externalTable = nullpt
1908 if (!inQuotes) {
1909 if (v == '(') parenDepth++;
1910 else if (v == ')') parenDepth--;
1911+
1912+ if (v == ':' || v == ';') continue;
1913 }
1914
1915 if (parenDepth > 0) {
1916diff --git a/tests/unitvalue.cc b/tests/unitvalue.cc
1917index 605943f..6bd824d 100644
1918--- a/tests/unitvalue.cc
1919+++ b/tests/unitvalue.cc
1920@@ -100,7 +100,7 @@ TEST_CASE("BENCH") {
1921 m.push_back(sym.get("height"),{UnitType::NUMBER, {.FLOAT = 700.0f}});
1922 m.push_back(sym.get("em"),{UnitType::NUMBER, {.FLOAT= 16.0f}});
1923
1924- std::vector<Unit> units = getUnit("let(x 10px) set(x (x + 100)) min(5 x)", &sym);
1925+ std::vector<Unit> units = getUnit("let(x 10px) set(x (x + 100)) (min(5 x) * 2)", &sym);
1926
1927 Snapshot s = m.save();
1928