home readme diff tree note docs

0commit 608704c468e4adf8e052f1695033bc225383485f
1Author: lakefox <mason@lakefox.net>
2Date:   Mon Jan 19 10:54:23 2026 -0700
3
4    Wrath VM working
5
6diff --git a/Makefile b/Makefile
7index 32afc3f..5197f09 100755
8--- a/Makefile
9+++ b/Makefile
10@@ -46,6 +46,11 @@ run_%: build/%
11 	@echo "--- Running $* ---"
12 	@./build/$* --skip-benchmarks
13 
14+bench_%: build/%
15+	@clear
16+	@echo "--- Running $* ---"
17+	@./build/$*
18+
19 build/css_unit_test: tests/css_unit.cc build/grim.o build/catch.o build/parser.o | build
20 	${CC} ${CCFLAGS} -Iinclude/ tests/css_unit.cc build/grim.o build/catch.o build/parser.o -o build/css_unit_test 
21 
22@@ -67,6 +72,9 @@ build/query_select_test: tests/query_select.cc build/grim.o build/parser.o build
23 build/windowunitlength_test: tests/windowunitlength.cc build/grim.o build/parser.o build/catch.o | build
24 	${CC} ${CCFLAGS} -Iinclude/ tests/windowunitlength.cc build/grim.o build/parser.o build/catch.o -o build/windowunitlength_test
25 
26+build/unitvalue_test: tests/unitvalue.cc build/grim.o build/parser.o build/catch.o | build
27+	${CC} ${CCFLAGS} -Iinclude/ tests/unitvalue.cc build/grim.o build/parser.o build/catch.o -o build/unitvalue_test
28+
29 
30 build/catch.o: ./include/catch_amalgamated.cpp ./include/catch_amalgamated.hpp | build
31 	${CC} ${CCFLAGS} -Iinclude/ -c include/catch_amalgamated.cpp -o build/catch.o
32@@ -87,6 +95,10 @@ build/css_unit_playground: playground/css_unit.cc build/grim.o build/parser.o |
33 build/window_playground: playground/window.cc build/grim.o build/parser.o | build
34 	${CC} ${CCFLAGS} -Iinclude/ playground/window.cc build/grim.o build/parser.o -o build/window_playground
35 
36+build/unitvalue_playground: playground/unitvalue.cc build/grim.o build/parser.o | build
37+	${CC} ${CCFLAGS} -Iinclude/ playground/unitvalue.cc build/grim.o build/parser.o -o build/unitvalue_playground
38+
39+
40 # --- Prebuild ---
41 
42 # use to prebuild the master.css
43diff --git a/include/grim.h b/include/grim.h
44index 19b86a2..e281f45 100755
45--- a/include/grim.h
46+++ b/include/grim.h
47@@ -17,7 +17,7 @@
48 
49 enum class UnitType : short {
50 	// Color
51-		TEST, HEX, RGB, RGBA, HSL,
52+		TEST, HEX, 
53 	// Logic
54 		AND, OR, NOT, ONLY, COMMA,
55 	// Length 
56@@ -72,8 +72,6 @@ enum class UnitType : short {
57 		SHORTER_HUE, LONGER_HUE, INCREASING_HUE, DECREASING_HUE, HUE,
58 	// Line Style
59 		DOTTED, DASHED, SOLID, DOUBLE, GROOVE, RIDGE, INSET, OUTSET,
60-	// Image
61-		URL, IMAGE_SET, CROSS_FADE, ELEMENT, GRADIENT,
62 	// Appearance																			 *Not added*
63 		MENU_LIST, TEXTFIELD, BASE_SELECT, BUTTON, CHECKBOX,
64 	// Space
65@@ -84,24 +82,32 @@ enum class UnitType : short {
66 		MULTIPLY, OVERLAY, DARKEN, LIGHTEN, COLOR_DODGE, COLOR_BURN, HARD_LIGHT, SOFT_LIGHT, DIFFERENCE, EXCLUSION, SATURATION, COLOR,  LUMINOSITY,
67 	// Background Clip
68 		BORDER_BOX, PADDING_BOX, CONTENT_BOX, TEXT, BORDER_AREA,
69-
70-
71-	// General Function
72-		CALC, MIN, MAX, CLAMP, ROUND, MOD, PROGRESS, REMD, POW, SQRT, HYPOT, LOG, EXP, ABS,
73-		SIGN, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, VAR,
74-		BLUR, BRIGHTNESS, CONTRAST, DROP_SHADOW, GRAYSCALE, HUE_ROTATE, INVERT, OPACITY, SEPIA, SATURATE,
75-		ATTR, TYPE, ENV, IF,
76-	// Easing Functions
77-		EASING_FUNCTION, LINEAR_EASING_FUNCTION, LINEAR, EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUBIC_BEZIER_FUNCTION, 
78-		STEP_START, STEP_END, STEPS_FUNCTION, JUMP_START, JUMP_END, JUMP_NONE, JUMP_BOTH, 
79-	// Transform Functions
80-		MATRIX,	MATRIX3D, PERSPECTIVE, ROTATE, ROTATE3D, ROTATEX, ROTATEY, ROTATEZ, SCALE, SCALE3D, SCALEX, SCALEY, SCALEZ, TRANSLATE, TRANSLATE3D, TRANSLATEX, TRANSLATEY, TRANSLATEZ, 
81-		SKEW, SKEWX, SKEWY,
82 	// Rounding
83 		NEAREST, UP, DOWN, TO_ZERO,	
84 
85 	// Keyword
86-		PRINT, SCREEN, TOKEN, FUNC, GROUP, NO_SUPPORT, IMAGE, STRING
87+		PRINT, SCREEN, TOKEN, NO_SUPPORT, IMAGE, STRING, BOOL,
88+
89+	FUNC_START,
90+		// General Functions
91+		CALC = FUNC_START, MIN, MAX, CLAMP, ROUND, MOD, PROGRESS, REMD, POW, SQRT, 
92+		HYPOT, LOG, EXP, ABS, SIGN, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, VAR,
93+		BLUR, BRIGHTNESS, CONTRAST, DROP_SHADOW, GRAYSCALE, HUE_ROTATE, INVERT, 
94+		OPACITY, SEPIA, SATURATE, ATTR, TYPE, ENV, IF, FUNC,
95+		
96+		// Easing Functions
97+		EASING_FUNCTION, LINEAR_EASING_FUNCTION, LINEAR, EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUBIC_BEZIER_FUNCTION, 
98+		STEP_START, STEP_END, STEPS_FUNCTION, JUMP_START, JUMP_END, JUMP_NONE, JUMP_BOTH, 	
99+
100+		// Transform Functions
101+		MATRIX, MATRIX3D, PERSPECTIVE, ROTATE, ROTATE3D, ROTATEX, ROTATEY, ROTATEZ, 
102+		SCALE, SCALE3D, SCALEX, SCALEY, SCALEZ, TRANSLATE, TRANSLATE3D, TRANSLATEX, 
103+		TRANSLATEY, TRANSLATEZ, SKEW, SKEWX, SKEWY,
104+
105+		RGB, RGBA, HSL,
106+		
107+		// Image & Grouping
108+		URL, IMAGE_SET, CROSS_FADE, ELEMENT, GRADIENT, GROUP,	
109 };
110 
111 
112@@ -115,11 +121,10 @@ union UnitValue {
113 	char CHAR;
114 };
115 
116-// 7 bytes 
117+// 8 bytes 
118 struct Unit {
119 	UnitType type; // short
120 	UnitValue value;
121-	bool isFunc;
122 };
123 
124 class Window;
125@@ -516,6 +521,6 @@ For the adapter, it will take a window as a argument to set the adapters capabil
126 Window createWindow();
127 
128 
129-float UnitLengthValue(Node*, Style*, const std::vector<Unit>&, size_t, size_t);
130+Unit UnitValue(Node*, Style*, const std::vector<Unit>&, size_t, size_t);
131 
132 #endif // NODE_H
133diff --git a/playground/unitlengthvalue.cc b/playground/unitvalue.cc
134similarity index 87%
135rename from playground/unitlengthvalue.cc
136rename to playground/unitvalue.cc
137index d8a79a5..fc38e68 100644
138--- a/playground/unitlengthvalue.cc
139+++ b/playground/unitvalue.cc
140@@ -47,7 +47,9 @@ int main() {
141 	document.cacheHeight(700);
142 	document.cacheEM(16);
143 
144-	std::vector<Unit> units = getUnit("mod(13px, 5px)");
145+	std::vector<Unit> units = getUnit(&window.CSS, "(3 >= (1 + 5))");
146 
147-	std::cout << UnitLengthValue(&document, units, 0, units.size()) << std::endl;
148+	Unit u = UnitValue(&document, &window.CSS, units, 0, units.size());
149+
150+	std::cout << u.value.BOOL << std::endl;
151 }
152diff --git a/src/grim.cc b/src/grim.cc
153index bbd3df0..5895fe4 100755
154--- a/src/grim.cc
155+++ b/src/grim.cc
156@@ -904,12 +904,9 @@ bool executeQuery(Window* w, std::string p) {
157 					if (v != MediaLookup.end()) {
158 						matches = k->second == v->second;
159 					}
160-				}/* else {
161-					if (k == "min-width") {
162-
163-						matches = w->getWidth() > 
164-					}
165-				}*/
166+				}
167+			} else {
168+				std::vector<Unit> units = getUnit(&w->CSS, key);
169 			}
170 		} else {
171 			// Lookup keyword
172@@ -930,77 +927,93 @@ struct Range {
173 	size_t end;
174 };
175 
176-std::vector<Range> extractUnits(const std::vector<Unit>& units, size_t start, size_t end) {
177-	std::vector<Range> u;
178-	for (size_t i = start; i < end; i++) {
179-		Unit unit = units[i];
180+Range getNextUnit(const std::vector<Unit>& units, size_t& offset, size_t end) {
181+    if (offset >= end) return {0, 0}; // Done
182 
183-		if (unit.isFunc) {
184-			u.push_back({i,i+unit.value.INT});
185-			i += unit.value.INT;
186-		} else {
187-			std::vector<Unit> s{unit};
188-			u.push_back({i, i+1});
189-		}
190-	}
191-	return u;
192+    size_t start = offset;
193+    const Unit& unit = units[offset];
194+
195+    if (unit.type > UnitType::FUNC_START) {
196+        // Range is the function unit + its body
197+        size_t argEnd = offset + unit.value.INT + 1;
198+        offset = argEnd; // Move offset past this function for next time
199+        return {start, argEnd};
200+    } else {
201+        offset += 1; // Move offset to next unit
202+        return {start, start + 1};
203+    }
204 }
205 
206-/*
207-	CAUTION: These values are only correct for top level media queries
208-*/
209-float UnitLengthValue(Node* n, Style* style, const std::vector<Unit>& units, size_t start, size_t end) {
210-	float sum = 0;
211+Unit UnitValue(Node* n, Style* style, const std::vector<Unit>& units, size_t start, size_t end) {
212+	Unit result{};
213+	result.type = UnitType::NUMBER;
214+	result.value.FLOAT = 0.0f;
215 	UnitType op = UnitType::ADD;
216 
217+	Unit iv;
218+	
219 	for (size_t i = start; i < end; i++) {
220 		Unit unit = units[i];
221 		UnitType type = unit.type;
222 
223-		float value = 0;
224-		float w = 0;
225-		float h = 0;
226-		float v1 = 0;
227-		float v2 = 0;
228-		float v3 = 0;
229-		std::vector<Range> extracted;
230-		UnitType ut;
231-		std::string s = "";
232-		bool b = false;
233 
234 		switch (type) {
235 			case UnitType::ADD:
236 			case UnitType::SUB:
237 			case UnitType::DIV:
238 			case UnitType::MULT:
239+			case UnitType::LT:
240+			case UnitType::LE:
241+			case UnitType::GT:
242+			case UnitType::GE:
243+			case UnitType::EQ:
244+			case UnitType::AND:
245+			case UnitType::OR:
246+			case UnitType::NOT:
247+			case UnitType::ONLY: {
248 				op = type;
249-				break;
250+				continue;
251+			}
252 			// DEG, TURN are not length values but are treated as generic units (PX)
253 			case UnitType::DEG:
254 			case UnitType::TURN:
255 			case UnitType::NUMBER:
256 				// NUMBER is any untyped numbers "2". Treat as a pixel
257-			case UnitType::PX:
258-				value = unit.value.FLOAT;
259+			case UnitType::PX: {
260+				iv.type = UnitType::NUMBER;
261+				iv.value.FLOAT = unit.value.FLOAT;
262 				break;
263-			case UnitType::CM:
264-				value = unit.value.FLOAT*37.8f;
265+			}
266+			case UnitType::CM: {
267+				iv.type = UnitType::NUMBER;
268+				iv.value.FLOAT = unit.value.FLOAT*37.8f;
269 				break;
270-			case UnitType::MM:
271-				value = unit.value.FLOAT*3.78f;
272+			}
273+			case UnitType::MM: {
274+				iv.type = UnitType::NUMBER;
275+				iv.value.FLOAT = unit.value.FLOAT*3.78f;
276 				break;
277-			case UnitType::Q:
278-				value = unit.value.FLOAT*0.94;
279+			}
280+			case UnitType::Q: {
281+				iv.type = UnitType::NUMBER;
282+				iv.value.FLOAT = unit.value.FLOAT*0.94f;
283 				break;
284-			case UnitType::IN:
285-				value = unit.value.FLOAT*96;
286+			}
287+			case UnitType::IN: {
288+				iv.type = UnitType::NUMBER;
289+				iv.value.FLOAT = unit.value.FLOAT*96.0f;
290 				break;
291-			case UnitType::PC:
292-				value = unit.value.FLOAT*16;
293+			}
294+			case UnitType::PC: {
295+				iv.type = UnitType::NUMBER;
296+				iv.value.FLOAT = unit.value.FLOAT*16.0f;
297 				break;
298-			case UnitType::PT:
299-				value = unit.value.FLOAT*1.3;
300+			}
301+			case UnitType::PT: {
302+				iv.type = UnitType::NUMBER;
303+				iv.value.FLOAT = unit.value.FLOAT*1.3f;
304 				break;
305+			}
306 			case UnitType::EM:
307 			case UnitType::REM:
308 			case UnitType::CAP:
309@@ -1011,379 +1024,532 @@ float UnitLengthValue(Node* n, Style* style, const std::vector<Unit>& units, siz
310 			case UnitType::RCAP:
311 			case UnitType::RCH:
312 			case UnitType::RIC:
313-			case UnitType::RLH:
314-				value = unit.value.FLOAT*n->getEM();
315+			case UnitType::RLH: {
316+				iv.type = UnitType::NUMBER;
317+				iv.value.FLOAT = unit.value.FLOAT*n->getEM();
318 				break;
319+			}
320 			case UnitType::EX:
321-			case UnitType::REX:
322-				value = unit.value.FLOAT*(n->getEM()/2);
323+			case UnitType::REX: {
324+				iv.type = UnitType::NUMBER;
325+				iv.value.FLOAT = unit.value.FLOAT*(n->getEM()*0.5f);
326 				break;
327+			}
328 			case UnitType::CQH:
329-			case UnitType::VH:
330-				value = n->getHeight()*(unit.value.FLOAT/100);
331+			case UnitType::VH: {
332+				iv.type = UnitType::NUMBER;
333+				iv.value.FLOAT = n->getHeight()*(unit.value.FLOAT*0.01f);
334 				break;
335+			}
336 			case UnitType::CQW:
337 			case UnitType::CQI:
338 			case UnitType::CQB:
339 			case UnitType::PERCENT:
340-			case UnitType::VW:	
341-				value = n->getWidth()*(unit.value.FLOAT/100);
342+			case UnitType::VW: {
343+				iv.type = UnitType::NUMBER;
344+				iv.value.FLOAT = n->getWidth()*(unit.value.FLOAT*0.01f);
345 				break;
346+			}
347 			case UnitType::VMAX:
348-			case UnitType::CQMAX:
349-				w = n->getWidth();
350-				h = n->getHeight();
351+			case UnitType::CQMAX: {
352+				iv.type = UnitType::NUMBER;
353+				float w = n->getWidth();
354+				float h = n->getHeight();
355 				if (w > h) {
356-					value = unit.value.FLOAT*w;
357+					iv.value.FLOAT = unit.value.FLOAT*w;
358 				} else {
359-					value = unit.value.FLOAT*h;
360+					iv.value.FLOAT = unit.value.FLOAT*h;
361 				}
362 				break;
363+			}
364 			case UnitType::VMIN:
365-			case UnitType::CQMIN:
366-				w = n->getWidth();
367-				h = n->getHeight();
368+			case UnitType::CQMIN: {
369+				iv.type = UnitType::NUMBER;
370+				float w = n->getWidth();
371+				float h = n->getHeight();
372 				if (w < h) {
373-					value = unit.value.FLOAT*w;
374+					iv.value.FLOAT = unit.value.FLOAT*w;
375 				} else {
376-					value = unit.value.FLOAT*h;
377+					iv.value.FLOAT = unit.value.FLOAT*h;
378 				}	
379 				break;
380+			}
381 			case UnitType::VB:
382-			case UnitType::VI:
383-				value = unit.value.FLOAT*n->getWidth();
384+			case UnitType::VI: {
385+				iv.type = UnitType::NUMBER;
386+				iv.value.FLOAT = unit.value.FLOAT*n->getWidth();
387+				break;
388+			}
389+			case UnitType::GROUP: {
390+			      	iv = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
391+				i += unit.value.INT;
392 				break;
393-			case UnitType::CALC:
394-				value = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
395+			}
396+			case UnitType::CALC: {
397+				iv.type = UnitType::NUMBER;
398+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
399+				iv.value.FLOAT = u1.value.FLOAT;
400 				i += unit.value.INT;
401 				break;
402-			case UnitType::MIN:
403-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
404+			}
405+			case UnitType::MIN: {
406+				iv.type = UnitType::NUMBER;
407 
408-				v1 = std::numeric_limits<float>::max(); // Store of the min value
409+				size_t start = i + 1;
410+				size_t end = i + 1 + unit.value.INT;
411 
412-				for (size_t j = 0; j < extracted.size(); j++) {
413-					v2 = UnitLengthValue(n, style, units, extracted[j].start, extracted[j].end);
414+				Range r = getNextUnit(units, start, end);
415+				iv.value.FLOAT = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
416 
417-					if (v2 < v1) {
418-						v1 = v2;
419-					}
420+				while (start < end) {
421+					r = getNextUnit(units, start, end);
422+					iv.value.FLOAT = std::min(iv.value.FLOAT, UnitValue(n, style, units, r.start, r.end).value.FLOAT);
423 				}
424 
425-				value = v1;
426-
427 				i += unit.value.INT;
428 				break;
429-			case UnitType::MAX:
430-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
431+			}
432+			case UnitType::MAX: {
433+				iv.type = UnitType::NUMBER;
434 
435-				v1 = std::numeric_limits<float>::min(); // Store of the max value
436+				size_t start = i + 1;
437+				size_t end = i + 1 + unit.value.INT;
438 
439-				for (size_t j = 0; j < extracted.size(); j++) {
440-					v2 = UnitLengthValue(n, style, units, extracted[j].start, extracted[j].end);
441+				Range r = getNextUnit(units, start, end);
442+				iv.value.FLOAT = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
443 
444-					if (v2 > v1) {
445-						v1 = v2;
446-					}
447+				while (start < end) {
448+					r = getNextUnit(units, start, end);
449+					iv.value.FLOAT = std::max(iv.value.FLOAT, UnitValue(n, style, units, r.start, r.end).value.FLOAT);
450 				}
451 
452-				value = v1;
453-
454 				i += unit.value.INT;
455-				break;		
456-			case UnitType::CLAMP:
457-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
458+				break;
459+			}
460+			case UnitType::CLAMP: {
461+				iv.type = UnitType::NUMBER;
462 
463-				if (extracted.size() >= 3) {
464-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
465-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
466-					v3 = UnitLengthValue(n, style, units, extracted[2].start, extracted[2].end);
467+				float args[3];
468+				int found = 0;
469+				size_t start = i + 1;
470+				size_t end = i + 1 + unit.value.INT;
471 
472-					if (v2 < v1) {
473-						v2 = v1;
474-					}
475-					if (v2 > v3) {
476-						v2 = v3;
477-					}
478+				while (start < end) {
479+					Range r = getNextUnit(units, start, end);
480+					args[found++] = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
481+				}
482 
483-					value = v2;
484+				if (found == 3) {
485+					iv.value.FLOAT = std::clamp(args[1], args[0], args[2]);
486+				} else {
487+					iv.value.FLOAT = args[0];
488 				}
489 				
490 				i += unit.value.INT;
491 				break;
492-			case UnitType::ROUND:
493-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
494+			}
495+			case UnitType::ROUND: {
496+				iv.type = UnitType::NUMBER;
497 
498-				ut = UnitType::NEAREST;
499+				UnitType ut = UnitType::NEAREST;
500 
501-				if (extracted.size() == 3) {
502-					ut = units[extracted[0].start].type;
503+				Unit args[3];
504+				int found = 0;
505+				size_t start = i + 1;
506+				size_t end = i + 1 + unit.value.INT;
507 
508-					v1 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
509-					v2 = UnitLengthValue(n, style, units, extracted[2].start, extracted[2].end);
510-				} else if (extracted.size() == 2) {
511+				while (start < end) {
512+					Range r = getNextUnit(units, start, end);
513+					args[found++] = UnitValue(n, style, units, r.start, r.end);
514+				}
515+
516+				if (found == 3) {
517+					ut = args[0].type;
518+
519+				} else if (found == 2) {
520 					ut = UnitType::NEAREST;
521 
522-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
523-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
524-				} else if (extracted.size() == 1) {
525+					args[2].value.FLOAT = args[1].value.FLOAT;
526+					args[1].value.FLOAT = args[0].value.FLOAT;
527+				} else if (found == 1) {
528 					ut = UnitType::NEAREST;
529 
530-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
531-					v2 = 1.0f;
532+					args[1].value.FLOAT = args[0].value.FLOAT;
533+					args[2].value.FLOAT = 1.0f;
534 				}
535 
536 
537 				if (ut == UnitType::NEAREST) {
538-					value = std::round(v1/v2)*v2; 
539+					iv.value.FLOAT = std::round(args[1].value.FLOAT/args[2].value.FLOAT)*args[2].value.FLOAT; 
540 				} else if (ut == UnitType::UP) {
541-					value = std::ceil(v1/v2)*v2; 
542+					iv.value.FLOAT = std::ceil(args[1].value.FLOAT/args[2].value.FLOAT)*args[2].value.FLOAT;
543 				} else if (ut == UnitType::DOWN) {
544-					value = std::floor(v1/v2)*v2; 
545+					iv.value.FLOAT = std::floor(args[1].value.FLOAT/args[2].value.FLOAT)*args[2].value.FLOAT; 
546 				} else if (ut == UnitType::TO_ZERO) {
547-					value = std::trunc(v1/v2)*v2; 
548+					iv.value.FLOAT = std::trunc(args[1].value.FLOAT/args[2].value.FLOAT)*args[2].value.FLOAT;
549 				}
550 
551 				i += unit.value.INT;
552 				break;
553-			case UnitType::MOD:
554-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
555+			}
556+			case UnitType::MOD: {
557+				iv.type = UnitType::NUMBER;
558 
559-				if (extracted.size() == 2) {
560-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
561-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
562+				float args[2];
563+				int found = 0;
564+				size_t start = i + 1;
565+				size_t end = i + 1 + unit.value.INT;
566 
567-					value = std::fmod(v1, v2);
568+				while (start < end) {
569+					Range r = getNextUnit(units, start, end);
570+					args[found++] = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
571+				}
572+
573+				if (found == 2) {
574+					iv.value.FLOAT = std::fmod(args[0], args[1]);
575+				} else {
576+					iv.value.FLOAT = args[0];
577 				}
578 
579 				i += unit.value.INT;
580 				break;
581-			case UnitType::PROGRESS:
582-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
583+			}
584+			case UnitType::PROGRESS: {
585+				iv.type = UnitType::NUMBER;
586 
587-				if (extracted.size() >= 3) {
588-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
589-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
590-					v3 = UnitLengthValue(n, style, units, extracted[2].start, extracted[2].end);
591+				float args[3];
592+				int found = 0;
593+				size_t start = i + 1;
594+				size_t end = i + 1 + unit.value.INT;
595 
596+				while (start < end) {
597+					Range r = getNextUnit(units, start, end);
598+					args[found++] = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
599+				}
600+
601+				if (found == 3) {
602 					// (progress - progress start) / (progress end - progress start)
603-					value = (v1-v2)/(v3-v2);
604+					iv.value.FLOAT = (args[0]-args[1])/(args[2]-args[1]);
605+				} else {
606+					iv.value.FLOAT = args[0];
607 				}
608 
609 				
610 				i += unit.value.INT;
611 				break;
612-			case UnitType::REMD:
613-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
614+			}
615+			case UnitType::REMD: {
616+				iv.type = UnitType::NUMBER;
617 
618-				if (extracted.size() == 2) {
619-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
620-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
621+				float args[2];
622+				int found = 0;
623+				size_t start = i + 1;
624+				size_t end = i + 1 + unit.value.INT;
625 
626-					value = std::fmodf(v1, v2);
627+				while (start < end) {
628+					Range r = getNextUnit(units, start, end);
629+					args[found++] = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
630+				}
631+
632+				if (found == 2) {
633+					iv.value.FLOAT = std::fmodf(args[0], args[1]);
634+				} else {
635+					iv.value.FLOAT = args[0];
636 				}
637 
638 				i += unit.value.INT;
639 				break;
640-			case UnitType::SIN:
641-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
642-				value = std::sinf(v1);
643+			}
644+			case UnitType::SIN: {
645+				iv.type = UnitType::NUMBER;
646+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
647+				iv.value.FLOAT = std::sinf(u1.value.FLOAT);
648 				i += unit.value.INT;
649 				break;
650-			case UnitType::COS:
651-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
652-				value = std::cosf(v1);
653+			}
654+			case UnitType::COS: {
655+				iv.type = UnitType::NUMBER;
656+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
657+				iv.value.FLOAT = std::cosf(u1.value.FLOAT);
658 				i += unit.value.INT;
659 				break;
660-			case UnitType::TAN:
661-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
662-				value = std::tanf(v1);
663+			}
664+			case UnitType::TAN: {
665+				iv.type = UnitType::NUMBER;
666+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
667+				iv.value.FLOAT = std::tanf(u1.value.FLOAT);
668 				i += unit.value.INT;
669 				break;
670-			case UnitType::ASIN:
671-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
672-				value = std::asinf(v1);
673+			}
674+			case UnitType::ASIN: {
675+				iv.type = UnitType::NUMBER;
676+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
677+				iv.value.FLOAT = std::asinf(u1.value.FLOAT);
678 				i += unit.value.INT;
679 				break;
680-			case UnitType::ACOS:
681-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
682-				value = std::acosf(v1);
683+			}
684+			case UnitType::ACOS: {
685+				iv.type = UnitType::NUMBER;
686+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
687+				iv.value.FLOAT = std::acosf(u1.value.FLOAT);
688 				i += unit.value.INT;
689 				break;
690-			case UnitType::ATAN:
691-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
692-				value = std::atanf(v1);
693+			}
694+			case UnitType::ATAN: {
695+				iv.type = UnitType::NUMBER;
696+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
697+				iv.value.FLOAT = std::atanf(u1.value.FLOAT);
698 				i += unit.value.INT;
699 				break;
700-			case UnitType::ATAN2:
701-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
702+			}
703+			case UnitType::ATAN2: {
704+				iv.type = UnitType::NUMBER;
705+
706+				float args[2];
707+				int found = 0;
708+				size_t start = i + 1;
709+				size_t end = i + 1 + unit.value.INT;
710 
711-				if (extracted.size() == 2) {
712-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
713-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
714+				while (start < end) {
715+					Range r = getNextUnit(units, start, end);
716+					args[found++] = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
717+				}
718 
719-					value = std::atan2f(v1, v2);
720+				if (found == 2) {
721+					iv.value.FLOAT = std::atan2f(args[0], args[1]);
722+				} else {
723+					iv.value.FLOAT = args[0];
724 				}
725+
726 				i += unit.value.INT;
727 				break;
728-			case UnitType::POW:
729-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
730+			}
731+			case UnitType::POW: {
732+				iv.type = UnitType::NUMBER;
733 
734-				if (extracted.size() == 2) {
735-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
736-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
737+				float args[2];
738+				int found = 0;
739+				size_t start = i + 1;
740+				size_t end = i + 1 + unit.value.INT;
741 
742-					value = std::powf(v1, v2);
743+				while (start < end) {
744+					Range r = getNextUnit(units, start, end);
745+					args[found++] = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
746 				}
747+
748+				if (found == 2) {
749+					iv.value.FLOAT = std::powf(args[0], args[1]);
750+				} else {
751+					iv.value.FLOAT = args[0];
752+				}
753+
754 				i += unit.value.INT;
755 				break;
756-			case UnitType::SQRT:
757-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
758-				value = std::sqrtf(v1);
759+			}
760+			case UnitType::SQRT: {
761+				iv.type = UnitType::NUMBER;
762+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
763+				iv.value.FLOAT = std::sqrtf(u1.value.FLOAT);
764 				i += unit.value.INT;
765 				break;
766-			case UnitType::HYPOT:
767-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
768+			}
769+			case UnitType::HYPOT: {
770+				iv.type = UnitType::NUMBER;
771 
772-				v2 = 0;
773-				for (size_t j = 0; j < extracted.size(); j++) {
774-					v1 = UnitLengthValue(n, style, units, extracted[j].start, extracted[j].end);
775 
776-					v2 += std::powf(v1, 2);
777+				float v = 0;
778+				size_t start = i + 1;
779+				size_t end = i + 1 + unit.value.INT;
780+
781+				while (start < end) {
782+					Range r = getNextUnit(units, start, end);
783+					float t = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
784+					v += t * t;
785 				}
786 
787-				value = std::sqrtf(v2);
788+				iv.value.FLOAT = std::sqrtf(v);
789 
790 				i += unit.value.INT;
791 				break;
792-			case UnitType::LOG:
793-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
794+			}
795+			case UnitType::LOG: {
796+				iv.type = UnitType::NUMBER;
797 
798-				if (extracted.size() == 2) {
799-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
800-					v2 = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
801+				float args[2];
802+				int found = 0;
803+				size_t start = i + 1;
804+				size_t end = i + 1 + unit.value.INT;
805 
806-					value = std::logf(v1) / std::logf(v2);
807-				} else if (extracted.size() == 1) {
808-					v1 = UnitLengthValue(n, style, units, extracted[0].start, extracted[0].end);
809+				while (start < end) {
810+					Range r = getNextUnit(units, start, end);
811+					args[found++] = UnitValue(n, style, units, r.start, r.end).value.FLOAT;
812+				}
813 
814-					value = std::logf(v1);
815+				if (found == 2) {
816+					iv.value.FLOAT = std::logf(args[0]) / std::logf(args[1]);
817+				} else if (found == 1) {
818+					iv.value.FLOAT = std::logf(args[0]);
819 				}
820 
821 				i += unit.value.INT;
822 				break;
823-			case UnitType::EXP:
824-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
825-				value = std::expf(v1);
826+			}
827+			case UnitType::EXP: {
828+				iv.type = UnitType::NUMBER;
829+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
830+				iv.value.FLOAT = std::expf(u1.value.FLOAT);
831 				i += unit.value.INT;
832 				break;
833-			case UnitType::ABS:
834-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
835-
836-				if (v1 < 0) v1 *= -1;
837-				value = v1;
838-				
839+			}
840+			case UnitType::ABS: {
841+				iv.type = UnitType::NUMBER;
842+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
843+				iv.value.FLOAT = std::fabsf(u1.value.FLOAT);
844 				i += unit.value.INT;
845 				break;
846-			case UnitType::SIGN:
847-				v1 = UnitLengthValue(n, style, units, i+1, i+1+unit.value.INT);
848-
849-				if (v1 > 0) {
850-					value = 1;
851-				} else if (v1 < 0) {
852-					value = -1;
853+			}
854+			case UnitType::SIGN: {
855+				iv.type = UnitType::NUMBER;
856+				Unit u1 = UnitValue(n, style, units, i+1, i+1+unit.value.INT);
857+
858+				if (u1.value.FLOAT > 0) {
859+					iv.value.FLOAT = 1;
860+				} else if (u1.value.FLOAT < 0) {
861+					iv.value.FLOAT = -1;
862 				} else {
863-					value = 0;
864+					iv.value.FLOAT = 0;
865 				}
866 
867 				i += unit.value.INT;
868 				break;
869-			case UnitType::ATTR:
870-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
871+			}
872+			case UnitType::ATTR: {
873+			     	Range args[3];
874+				int found = 0;
875+				size_t start = i + 1;
876+				size_t end = i + 1 + unit.value.INT;
877+
878+				while (start < end) {
879+					args[found++] = getNextUnit(units, start, end);
880+				}
881+
882+				Unit u1 = UnitValue(n, style, units, args[0].start, args[0].end);
883 
884-				if (units[extracted[0].start].type == UnitType::VAR) {
885-					b = n->hasAttribute(style->variables.key(units[extracted[0].start].value.INT));
886-					s = n->getAttribute(style->variables.key(units[extracted[0].start].value.INT));
887+				if (u1.type == UnitType::VAR) {
888+					bool has = n->hasAttribute(style->variables.key(u1.value.INT));
889+					std::string value = n->getAttribute(style->variables.key(u1.value.INT));
890 
891-					if (!s.empty() && b) {
892+					if (!value.empty() && has) {
893 						// attr(size px, 10)
894 						// s = n->getAttribute(size) size="20"
895-						std::vector<Unit> us = getUnit(style, s);
896+						std::vector<Unit> us = getUnit(style, value);
897 						// us = {NUMBER, 20}
898 						// extracted[1] == {type: PX} || {type::TYPE}
899 						// Add the type of the next if the type is inside of type(px) or just add the type px
900-						if (extracted.size() > 1) {
901-							if (units[extracted[1].start].type == UnitType::TYPE) {
902-								us[0].type = units[extracted[1].start+1].type;
903+						if (found > 1) {
904+							Unit u2 = UnitValue(n, style, units, args[1].start, args[1].end);
905+
906+							if (u2.type == UnitType::TYPE) {
907+								us[0].type = units[args[1].start+1].type;
908 							} else {
909-								us[0].type = units[extracted[1].start].type;
910+								us[0].type = u2.type;
911 							}
912 						}
913 						
914-						value = UnitLengthValue(n, style, us, 0, us.size());
915-					} else if (extracted.size() == 3) {
916+						iv = UnitValue(n, style, us, 0, us.size());
917+					} else if (found == 3) {
918 						// Default value
919-						value = UnitLengthValue(n, style, units, extracted[6].start, extracted[2].end);
920+						iv = UnitValue(n, style, units, args[2].start, args[2].end);
921 					}
922 				}
923 
924 				i += unit.value.INT;
925 				break;
926-			case UnitType::VAR:
927-				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
928+			}
929+			case UnitType::VAR: {
930+				Unit args[2];
931+				int found = 0;
932+				size_t start = i + 1;
933+				size_t end = i + 1 + unit.value.INT;
934+
935+				while (start < end) {
936+					Range r = getNextUnit(units, start, end);
937+					args[found++] = UnitValue(n, style, units, r.start, r.end);
938+				}
939 
940-				if (units[extracted[0].start].type == UnitType::VAR) {
941+				if (args[0].type == UnitType::VAR) {
942 					// Variables flow down during processing so theres no need to check above
943-					std::vector<Unit> us = style->variables.at(units[extracted[0].start].value.INT);
944+					std::vector<Unit> us = style->variables.at(args[0].value.INT);
945 
946 					if (us.size() > 0) {
947-						value = UnitLengthValue(n, style, us, 0, us.size());
948-					} else if (extracted.size() == 2) {
949+						iv = UnitValue(n, style, us, 0, us.size());
950+					} else if (found == 2) {
951 						// Default value
952-						value = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
953+						iv = args[1];
954 					}
955 				}
956 
957 				i += unit.value.INT;
958 				break;
959-
960-
961-
962-
963-
964-
965-
966-
967-												// Why not make this just get unit value and return a unit?
968-
969-
970-
971-
972-
973-
974-
975-			// Need to add variable injection and group handling
976+			}
977 		}
978 
979-		if (op != type) {
980+		if (iv.type == UnitType::NUMBER) {
981 			switch (op) {
982 				case UnitType::ADD:
983-					sum += value;
984+					result.value.FLOAT += iv.value.FLOAT;
985 					break;
986 				case UnitType::SUB:
987-					sum -= value;
988+					result.value.FLOAT -= iv.value.FLOAT;
989 					break;
990 				case UnitType::DIV:
991-					sum /= value;
992+					result.value.FLOAT /= iv.value.FLOAT;
993 					break;
994 				case UnitType::MULT:
995-					sum *= value;
996+					result.value.FLOAT *= iv.value.FLOAT;
997+					break;
998+				case UnitType::LT:
999+					result.type = UnitType::BOOL;
1000+					result.value.BOOL = result.value.FLOAT < iv.value.FLOAT;
1001+					break;
1002+				case UnitType::GT:
1003+					result.type = UnitType::BOOL;
1004+					result.value.BOOL = result.value.FLOAT > iv.value.FLOAT;
1005+					break;
1006+				case UnitType::LE:
1007+					result.type = UnitType::BOOL;
1008+					result.value.BOOL = result.value.FLOAT <= iv.value.FLOAT;
1009+					break;
1010+				case UnitType::GE:
1011+					result.type = UnitType::BOOL;
1012+					result.value.BOOL = result.value.FLOAT >= iv.value.FLOAT;
1013+					break;
1014+				case UnitType::EQ:
1015+					result.type = UnitType::BOOL;
1016+					result.value.BOOL = result.value.FLOAT == iv.value.FLOAT;
1017 					break;
1018 			}
1019+		} else if (iv.type == UnitType::BOOL) {
1020+			result.type = UnitType::BOOL;
1021+			switch (op) {
1022+				case UnitType::AND:
1023+					result.value.BOOL = result.value.BOOL && iv.value.BOOL;
1024+					break;
1025+				case UnitType::OR:
1026+					result.value.BOOL = result.value.BOOL || iv.value.BOOL;
1027+					break;
1028+				case UnitType::NOT:
1029+					result.value.BOOL = !iv.value.BOOL;
1030+					break;
1031+				case UnitType::EQ:
1032+					result.value.BOOL = result.value.BOOL == iv.value.BOOL;
1033+				default:
1034+					result.value.BOOL = iv.value.BOOL;
1035+			}
1036 		}
1037 	}
1038-	
1039-	return sum;
1040+
1041+	return result;
1042 }
1043 
1044 // Used for root node without a parent
1045diff --git a/src/parser.cc b/src/parser.cc
1046index e5f027a..fca724a 100755
1047--- a/src/parser.cc
1048+++ b/src/parser.cc
1049@@ -836,6 +836,13 @@ static const std::unordered_map<std::string_view, UnitType> kMatch{
1050 	{"<", UnitType::LT},
1051 	{">=", UnitType::GE},
1052 	{"<=", UnitType::LE},
1053+	{"and", UnitType::AND},
1054+	{"&&", UnitType::AND},
1055+	{"or", UnitType::OR},
1056+	{"||", UnitType::OR},
1057+	{"not", UnitType::NOT},
1058+	{"!=", UnitType::NOT},
1059+	{"only", UnitType::ONLY},
1060 	{"infinity", UnitType::INF},
1061 	{"-infinity", UnitType::NEGINF},
1062 	{"NaN", UnitType::NaN},
1063@@ -1058,7 +1065,6 @@ std::vector<Unit> getUnit(Style* s, std::string value) {
1064 
1065 				Unit unit{};
1066 				unit.type = UnitType::STRING;
1067-				unit.isFunc = false;
1068 				unit.value.INT = s->strings.size()-1;
1069 				units.push_back(unit);
1070 
1071@@ -1099,10 +1105,11 @@ std::vector<Unit> getUnit(Style* s, std::string value) {
1072 			std::vector<Unit> children = getUnit(s, value);
1073 			
1074 			Unit unit;
1075-			unit.isFunc = true;
1076 
1077 			if (auto it = kFunc.find(name); it != kFunc.end()) { 
1078 				unit.type = it->second;
1079+			} else {
1080+				unit.type = UnitType::FUNC;
1081 			}
1082 
1083 			// The value of the function is the child count
1084@@ -1117,7 +1124,6 @@ std::vector<Unit> getUnit(Style* s, std::string value) {
1085 			if (v != ',' && !std::isspace(v)) buffer.push_back(v);
1086 
1087 			Unit unit;
1088-			unit.isFunc = false;
1089 
1090 			// Split by spaces into parts
1091 
1092diff --git a/tests/unitvalue.cc b/tests/unitvalue.cc
1093new file mode 100644
1094index 0000000..aac413c
1095--- /dev/null
1096+++ b/tests/unitvalue.cc
1097@@ -0,0 +1,88 @@
1098+#include <catch_amalgamated.hpp>
1099+#include "../include/grim.h"
1100+#include "../include/parser.h" 
1101+#include <string>
1102+#include <sstream>
1103+#include <vector>
1104+
1105+TEST_CASE("Benchmark UnitValue evaluation", "[performance][grim]") {
1106+	Window window = createWindow();
1107+
1108+	Node document = window.document;
1109+	document.cacheWidth(1000);
1110+	document.cacheHeight(700);
1111+	document.cacheEM(16);
1112+
1113+	SECTION("(3 >= min(1, 5)") {
1114+		std::vector<Unit> units = getUnit(&window.CSS, "(3 >= min(1, 5))");
1115+
1116+		REQUIRE(UnitValue(&document, &window.CSS, units, 0, units.size()).value.BOOL);
1117+	}
1118+}
1119+
1120+TEST_CASE("UnitValue Logic and Math", "[grim][logic]") {
1121+    Window window = createWindow();
1122+    Node document = window.document;
1123+    document.cacheWidth(1000); // 1vw = 10px
1124+    document.cacheHeight(500); // 1vh = 5px
1125+    document.cacheEM(16);      // 1em = 16px
1126+
1127+    SECTION("Math Operators and Precedence (Group)") {
1128+        // (10 + 2 * 5) -> In your linear engine, without GROUP this is 60.
1129+        // With GROUP: (10 + (2 * 5)) = 20
1130+        std::vector<Unit> units = getUnit(&window.CSS, "(10 + (2 * 5))");
1131+        auto res = UnitValue(&document, &window.CSS, units, 0, units.size());
1132+        REQUIRE(res.value.FLOAT == 20.0f);
1133+    }
1134+
1135+    SECTION("CSS Units Conversion") {
1136+        // 1in = 96px, 1cm = 37.8px
1137+        std::vector<Unit> units = getUnit(&window.CSS, "1in + 4px");
1138+        auto res = UnitValue(&document, &window.CSS, units, 0, units.size());
1139+        REQUIRE(res.value.FLOAT == 100.0f);
1140+    }
1141+
1142+    SECTION("Viewport Units") {
1143+        // 50vw (500px) + 10vh (50px) = 550px
1144+        std::vector<Unit> units = getUnit(&window.CSS, "50vw + 10vh");
1145+        auto res = UnitValue(&document, &window.CSS, units, 0, units.size());
1146+        REQUIRE(res.value.FLOAT == 550.0f);
1147+    }
1148+
1149+    SECTION("Clamping and Min/Max") {
1150+        // clamp(100, 50, 200) -> 100 (50 is below min)
1151+        std::vector<Unit> units = getUnit(&window.CSS, "clamp(100, 50, 200)");
1152+        auto res = UnitValue(&document, &window.CSS, units, 0, units.size());
1153+        REQUIRE(res.value.FLOAT == 100.0f);
1154+
1155+        // max(10, 20, 30, 5) -> 30
1156+        units = getUnit(&window.CSS, "max(10, 20, 30, 5)");
1157+        res = UnitValue(&document, &window.CSS, units, 0, units.size());
1158+        REQUIRE(res.value.FLOAT == 30.0f);
1159+    }
1160+
1161+    SECTION("Logical Operators (Boolean)") {
1162+        // (10 > 5) AND (2 <= 2) -> true
1163+        std::vector<Unit> units = getUnit(&window.CSS, "(10 > 5) and (2 <= 2)");
1164+        auto res1 = UnitValue(&document, &window.CSS, units, 0, units.size());
1165+        REQUIRE(res1.type == UnitType::BOOL);
1166+        REQUIRE(res1.value.BOOL == true);
1167+
1168+        // (10 < 5) OR (1 == 1) -> true
1169+        units = getUnit(&window.CSS, "(10 < 5) or (1 == 1)");
1170+        auto res2 = UnitValue(&document, &window.CSS, units, 0, units.size());
1171+        REQUIRE(res2.value.BOOL == true);
1172+    }
1173+
1174+    SECTION("Deep Recursion Stress") {
1175+	    // (((1 + 1) + 1) + 1) ...
1176+	    std::string deep = "(1 + (1 + (1 + (1 + (1 + (1 + 1))))))";
1177+	    std::vector<Unit> units = getUnit(&window.CSS, deep);
1178+
1179+	    BENCHMARK("Deep Math Recursion") {
1180+		return UnitValue(&document, &window.CSS, units, 0, units.size());
1181+	    };
1182+    }
1183+}
1184+
1185+