home readme diff tree note docs

0commit b99dd0a8bf911b83adf04c1f0453dba6051c0c5a
1Author: lakefox <mason@lakefox.net>
2Date:   Sat Feb 28 19:55:17 2026 -0700
3
4    Added arg counting to parser
5
6diff --git a/include/grim.h b/include/grim.h
7index 08d8c61..1377ea8 100755
8--- a/include/grim.h
9+++ b/include/grim.h
10@@ -15,8 +15,6 @@
11 typedef enum {
12 	// Color
13 		TEST, HEX, 
14-	// Logic
15-		AND, OR, NOT, ONLY, COMMA,
16 	// Length 
17 		PX, EM, PERCENT, CM, CAP, CH, EX, IC, LH, RCAP, RCH, REM, REX, RIC, RLH, VH, 
18 		VW, VMAX, VMIN, VB, VI, CQW, CQH, CQI, CQB, CQMIN, CQMAX, MM, Q, IN, PC, PT,
19@@ -31,8 +29,6 @@ typedef enum {
20 
21 	// Global
22 		INHERIT, INITIAL, REVERT, REVERT_LAYER, UNSET, AUTO, NONE,
23-	// Operator 
24-		EQ, LT, GT, LE, GE, ADD, SUB, MULT, DIV,
25 	// Baseline Position
26 		FIRST_BASELINE, LAST_BASELINE,
27 	// Box Edge
28@@ -83,7 +79,7 @@ typedef enum {
29 		NEAREST, UP, DOWN, TO_ZERO,	
30 
31 	// Keyword
32-		PRINT, SCREEN, TOKEN, NO_SUPPORT, IMAGE, STRING, BOOL, VAR, NONOP, ELSE, TAG, CHAR,
33+		SCREEN, TOKEN, NO_SUPPORT, IMAGE, STRING, BOOL, VAR, NONOP, ELSE, TAG, CHAR,
34 
35 	FUNC_START,
36 		// General Functions
37@@ -91,7 +87,7 @@ typedef enum {
38 		HYPOT, LOG, EXP, ABS, SIGN, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, VAR_FUNC,
39 		BLUR, BRIGHTNESS, CONTRAST, DROP_SHADOW, GRAYSCALE, HUE_ROTATE, INVERT, 
40 		OPACITY, SEPIA, SATURATE, ATTR, TYPE, ENV, IF, FUNC, LET, RETURN, SET,
41-		LIST, AT, EMPTY, INSERT, SIZE, WHILE,
42+		LIST, AT, EMPTY, INSERT, SIZE, WHILE, PRINT,  
43 		
44 		// Easing Functions
45 		EASING_FUNCTION, LINEAR_EASING_FUNCTION, LINEAR, EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUBIC_BEZIER_FUNCTION, 
46@@ -106,6 +102,12 @@ typedef enum {
47 		
48 		// Image & Grouping
49 		URL, IMAGE_SET, CROSS_FADE, ELEMENT, GROUP, GRADIENT,
50+
51+	// Operator 
52+		EQ, LT, GT, LE, GE, ADD, SUB, MULT, DIV,
53+
54+	// Logic
55+		AND, OR, NOT, ONLY, COMMA,
56 	NON_FUNC_PADDING
57 } UnitType;
58 
59diff --git a/playground/css_unit.c b/playground/css_unit.c
60index 63aef74..cb819b1 100644
61--- a/playground/css_unit.c
62+++ b/playground/css_unit.c
63@@ -116,23 +116,36 @@ int main() {
64 	free(vars);
65 
66 	if (true) {
67-		benchmark_get_unit(ustr);
68+		//benchmark_get_unit(ustr);
69+
70+		test_get_unit("1 + 1", (struct Unit[]){{NUMBER, 1}, {NUMBER, 1}, {ADD, 2}}, 3, 0, 2);
71+		test_get_unit("23px * 5678.7%", (struct Unit[]){{PX, 23}, {PERCENT, 5678.7f}, {MULT, 2}}, 3, 0, 2);
72+		test_get_unit("calc(23px * size)", (struct Unit[]){{PX, 23}, {VAR, -1}, {MULT, 2}, {CALC, 1}}, 4, 0, 3);
73+		test_get_unit("(let(x 10px) set(x 30px) (let(x 50px) print(x)) print(x))", (struct Unit[]){{VAR, 0}, {PX, 10}, {LET, 2}, {VAR, 0}, {PX, 30}, {SET, 2}, {VAR, 1}, {PX, 50}, {LET, 2}, {VAR, 1}, {PRINT, 1}, {GROUP, 2}, {VAR, 0}, {PRINT, 1}, {GROUP, 4}}, 15, 2, 14);
74+	//	test_get_unit("(min(x 10px) set(x 30px) (min(x 50px) print(x)) print(x))", (struct Unit[]){{VAR, -1}, {PX, 10}, {MIN, 2}, {VAR, -1}, {PX, 30}, {SET, 2}, {VAR, -1}, {PX, 50}, {MIN, 2}, {VAR, -1}, {PRINT, 1}, {GROUP, 2}, {VAR, -1}, {PRINT, 1}, {GROUP, 4}}, 15, 0, 14);
75+
76+
77+
78+
79+
80 
81-		test_get_unit("1 + 1", (struct Unit[]){{NUMBER, 1}, {NUMBER, 1}, {ADD, 0}}, 3, 0, 2);
82-		test_get_unit("23px * 5678.7%", (struct Unit[]){{PX, 23}, {PERCENT, 5678.7f}, {MULT, 0}}, 3, 0, 2);
83-		test_get_unit("calc(23px * size)", (struct Unit[]){{PX, 23}, {VAR, -1}, {MULT, 0}, {CALC, 3}}, 4, 0, 3);
84-		test_get_unit("(let(x 10px) set(x 30px) (let(x 50px) print(x)) print(x))", (struct Unit[]){{VAR, 0}, {PX, 10}, {LET, 2}, {VAR, 0}, {PX, 30}, {SET, 2}, {VAR, 1}, {PX, 50}, {LET, 2}, {VAR, 1}, {PRINT, 1}, {GROUP, 5}, {VAR, 0}, {PRINT, 1}, {GROUP, 14}}, 15, 2, 14);
85 		test_get_unit("((let(x 10px) set(x x * 2%) print(x)) (let(y 10px) set(y y * 2) print(y)))", (struct Unit[]){ 
86-				{VAR, 0}, {PX, 10}, {LET, 2},
87-				{VAR, 0}, {VAR, 0}, {PERCENT, 2}, {MULT, 0}, {SET, 4},
88-				{VAR, 0}, {PRINT, 1},
89-			{GROUP, 10}, 
90-				{ VAR, 0}, {PX, 10}, {LET, 2},
91-				{VAR, 0}, {VAR, 0}, {NUMBER, 2}, {MULT, 0}, {SET, 4},
92-				{VAR, 0}, {PRINT, 1},
93-			{GROUP, 10}, 
94-		{GROUP, 22}}
95-			, 23, 1, 22);
96-		test_get_unit("(let(x :name \"john doe\" :age 27))", (struct Unit[]){{VAR, 0}, {TAG, 1035}, {STRING, 8}, {CHAR, 106}, {CHAR, 111}, {CHAR, 104}, {CHAR, 110}, {CHAR, 32}, {CHAR, 100}, {CHAR, 111}, {CHAR, 101}, {TAG, 606}, {NUMBER, 27}, {LET, 13}, {GROUP, 14}}, 15, 1, 14);
97+					{VAR, 0}, {PX, 10}, {LET, 2},
98+					{VAR, 0}, {VAR, 0}, {PERCENT, 2}, {MULT, 2}, {SET, 2},
99+					{VAR, 0}, {PRINT, 1},
100+				{GROUP, 3}, 
101+					{ VAR, 0}, {PX, 10}, {LET, 2},
102+					{VAR, 0}, {VAR, 0}, {NUMBER, 2}, {MULT, 2}, {SET, 2},
103+					{VAR, 0}, {PRINT, 1},
104+				{GROUP, 3}, 
105+			{GROUP, 2}}
106+		, 23, 1, 22);
107+
108+
109+
110+
111+
112+
113+		test_get_unit("(let(x :name \"john doe\" :age 27))", (struct Unit[]){{VAR, 0}, {TAG, 1035}, {STRING, 8}, {CHAR, 106}, {CHAR, 111}, {CHAR, 104}, {CHAR, 110}, {CHAR, 32}, {CHAR, 100}, {CHAR, 111}, {CHAR, 101}, {TAG, 606}, {NUMBER, 27}, {LET, 13}, {GROUP, 1}}, 15, 1, 14);
114 	}
115 }
116diff --git a/src/grim.c b/src/grim.c
117index 9ecb714..a375ea7 100755
118--- a/src/grim.c
119+++ b/src/grim.c
120@@ -451,7 +451,9 @@ Range getNextUnit(const std::vector<Unit>& units, size_t& offset, size_t end) {
121 float unit_value(struct Units[]** stack, int register_size, int heap_size, struct Unit** units, int* units_len) {
122 	struct Unit** heap[heap_size];
123 	int heap[heap_size] = {0};
124+
125 	struct Unit registers[register_size] = {0};
126+	int register_len = 0;
127 
128 	// Pre-alloc
129 	for (int i = 0; i < heap_size; i++) {
130@@ -465,60 +467,44 @@ float unit_value(struct Units[]** stack, int register_size, int heap_size, struc
131 
132 		if (value range to put to register)
133 		switch (type) {
134-			case ADD:
135-			case SUB:
136-			case DIV:
137-			case MULT:
138-			case LT:
139-			case LE:
140-			case GT:
141-			case GE:
142-			case EQ:
143-			case AND:
144-			case OR:
145-			case NOT:
146-			case ONLY: {
147-				op = type;
148-				continue;
149-			}
150 			// DEG, TURN are not length values but are treated as generic units (PX)
151 			case DEG:
152 			case TURN:
153 			case NUMBER:
154 				// NUMBER is any untyped numbers "2". Treat as a pixel
155 			case PX: {
156-				iv.type = NUMBER;
157-				iv.value = unit.value;
158+				register[register_len].type = NUMBER;
159+				register[register_len++].value = unit.value;
160 				break;
161 			}
162 			case CM: {
163-				iv.type = NUMBER;
164-				iv.value = unit.value*37.8f;
165+				register[register_len].type = NUMBER;
166+				register[register_len++].value = unit.value*37.8f;
167 				break;
168 			}
169 			case MM: {
170-				iv.type = NUMBER;
171-				iv.value = unit.value*3.78f;
172+				register[register_len].type = NUMBER;
173+				register[register_len++].value = unit.value*3.78f;
174 				break;
175 			}
176 			case Q: {
177-				iv.type = NUMBER;
178-				iv.value = unit.value*0.94f;
179+				register[register_len].type = NUMBER;
180+				register[register_len++].value = unit.value*0.94f;
181 				break;
182 			}
183 			case IN: {
184-				iv.type = NUMBER;
185-				iv.value = unit.value*96.0f;
186+				register[register_len].type = NUMBER;
187+				register[register_len++].value = unit.value*96.0f;
188 				break;
189 			}
190 			case PC: {
191-				iv.type = NUMBER;
192-				iv.value = unit.value*16.0f;
193+				register[register_len].type = NUMBER;
194+				register[register_len++].value = unit.value*16.0f;
195 				break;
196 			}
197 			case PT: {
198-				iv.type = NUMBER;
199-				iv.value = unit.value*1.3f;
200+				register[register_len].type = NUMBER;
201+				register[register_len++].value = unit.value*1.3f;
202 				break;
203 			}
204 			case EM:
205@@ -532,20 +518,20 @@ float unit_value(struct Units[]** stack, int register_size, int heap_size, struc
206 			case RCH:
207 			case RIC:
208 			case RLH: {
209-				iv.type = NUMBER;
210-				iv.value = unit.value*stack[2].value;
211+				register[register_len].type = NUMBER;
212+				register[register_len++].value = unit.value*stack[2].value;
213 				break;
214 			}
215 			case EX:
216 			case REX: {
217-				iv.type = NUMBER;
218-				iv.value = unit.value*(heap.units[2].value*0.5f);
219+				register[register_len].type = NUMBER;
220+				register[register_len++].value = unit.value*(heap.units[2].value*0.5f);
221 				break;
222 			}
223 			case CQH:
224 			case VH: {
225-				iv.type = NUMBER;
226-				iv.value = heap.units[1].value*(unit.value*0.01f);
227+				register[register_len].type = NUMBER;
228+				register[register_len++].value = heap.units[1].value*(unit.value*0.01f);
229 				break;
230 			}
231 			case CQW:
232@@ -553,92 +539,67 @@ float unit_value(struct Units[]** stack, int register_size, int heap_size, struc
233 			case CQB:
234 			case PERCENT:
235 			case VW: {
236-				iv.type = NUMBER;
237-				iv.value = heap.units[0].value*(unit.value*0.01f);
238+				register[register_len].type = NUMBER;
239+				register[register_len++].value = heap.units[0].value*(unit.value*0.01f);
240 				break;
241 			}
242 			case VMAX:
243 			case CQMAX: {
244-				iv.type = NUMBER;
245+				register[register_len].type = NUMBER;
246 				// 0: width
247 				// 1: height
248 				if (heap.units[0].value > heap.units[1].value) {
249-					iv.value = unit.value*heap.units[0].value;
250+					register[register_len++].value = unit.value*heap.units[0].value;
251 				} else {
252-					iv.value = unit.value*heap.units[1].value;
253+					register[register_len++].value = unit.value*heap.units[1].value;
254 				}
255 				break;
256 			}
257 			case VMIN:
258 			case CQMIN: {
259-				iv.type = NUMBER;
260+				register[register_len].type = NUMBER;
261 				if (heap.units[0].value < heap.units[1].value) {
262-					iv.value = unit.value*heap.units[0].value;
263+					register[register_len++].value = unit.value*heap.units[0].value;
264 				} else {
265-					iv.value = unit.value*heap.units[1].value;
266+					register[register_len++].value = unit.value*heap.units[1].value;
267 				}	
268 				break;
269 			}
270 			case VB:
271 			case VI: {
272-				iv.type = NUMBER;
273-				iv.value = unit.value*heap.units[0].value;
274+				register[register_len].type = NUMBER;
275+				register[register_len++].value = unit.value*heap.units[0].value;
276 				break;
277 			}
278-
279-
280-
281-
282-
283-if func range
284-
285 			case GROUP: {
286-				Snapshot s = m.save();
287-				iv = UnitValue(m, units, i+1, i+1+unit.value);
288-				i += unit.value;
289-				m.restore(s);
290+				// Just returns the first value on the register stack
291+				register_len = 1;
292 				break;
293 			}
294 			case CALC: {
295-				iv.type = NUMBER;
296-				Unit u1 = UnitValue(m, units, i+1, i+1+unit.value);
297-				iv.value = u1.value;
298-				i += unit.value;
299+				// Because the calculation would have already ran, make sure the first value is a number
300+				registers[0].type = NUMBER;
301+				register_len = 1;
302 				break;
303 			}
304 			case MIN: {
305-				iv.type = NUMBER;
306+				registers[0].type = NUMBER;
307 
308-				size_t start = i + 1;
309-				size_t end = i + 1 + unit.value;
310-
311-				Range r = getNextUnit(units, start, end);
312-				iv.value = UnitValue(m, units, r.start, r.end).value;
313-
314-				while (start < end) {
315-					r = getNextUnit(units, start, end);
316-					float u = UnitValue(m, units, r.start, r.end).value;
317-					iv.value = std::min(iv.value, u);
318+				for (int j = 1; j < register_len; j++) {
319+					if (registers[0] > registers[j]) {
320+						registers[0] = registers[j];
321+					}
322 				}
323-
324-				i += unit.value;
325 				break;
326 			}
327 			case MAX: {
328-				iv.type = NUMBER;
329-
330-				size_t start = i + 1;
331-				size_t end = i + 1 + unit.value;
332+				registers[0].type = NUMBER;
333 
334-				Range r = getNextUnit(units, start, end);
335-				iv.value = UnitValue(m, units, r.start, r.end).value;
336-
337-				while (start < end) {
338-					r = getNextUnit(units, start, end);
339-					iv.value = std::max(iv.value, UnitValue(m, units, r.start, r.end).value);
340+				for (int j = 1; j < register_len; j++) {
341+					if (registers[0] < registers[j]) {
342+						registers[0] = registers[j];
343+					}
344 				}
345-
346-				i += unit.value;
347 				break;
348 			}
349 			case CLAMP: {
350@@ -1184,9 +1145,12 @@ if func range
351 				i += unit.value;
352 				break;
353 			}
354-		}
355 
356-		switch (op) {
357+
358+
359+
360+
361+
362 			case ADD:
363 				result.type = NUMBER;
364 				result.value += iv.value;
365diff --git a/src/parser.c b/src/parser.c
366index 8b15503..533cf00 100755
367--- a/src/parser.c
368+++ b/src/parser.c
369@@ -252,13 +252,28 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
370 				*vars_len = before_vars_len;
371 			}
372 
373-			int child_count = *units_len - before_count;
374+			int reg_count = *units_len - before_count;
375 
376-			if (child_count > *max_register_size) {
377-				*max_register_size = child_count;
378+			if (reg_count > *max_register_size) {
379+				*max_register_size = reg_count;
380 			}
381 
382-			placeholder.value = (float)child_count;
383+			float child_count = 0;
384+			float depth = 0;
385+			
386+			for (int j = *units_len-1; j >= before_count; j--) {
387+				if ((*units)[j].type >= FUNC_START) {
388+					depth += (*units)[j].value;
389+				}
390+
391+				if (depth == 0) {
392+					child_count++;
393+				} else {
394+					depth--;
395+				}
396+			}
397+
398+			placeholder.value = child_count;
399 
400 			write_unit(units, units_len, cap, placeholder);
401 
402@@ -412,6 +427,7 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
403 						(*units)[(*units_len)-1].type == NOT 
404 				)) {
405 				struct Unit u = (*units)[(*units_len)-1];
406+				u.value = 2;
407 				(*units_len) -= 1;
408 				write_unit(units, units_len, cap, unit);
409 				write_unit(units, units_len, cap, u);