home readme diff tree note docs

0commit 6deac78948b540343ed23fb6403ea176c6b2ecf0
1Author: lakefox <mason@lakefox.net>
2Date:   Sun Feb 22 15:36:57 2026 -0700
3
4    get_unit fixes
5
6diff --git a/playground/css_unit.c b/playground/css_unit.c
7index cfe9a19..dae4828 100644
8--- a/playground/css_unit.c
9+++ b/playground/css_unit.c
10@@ -42,13 +42,13 @@ void benchmark_get_unit(char* value) {
11 	       (total_time / iterations) * 1000000);
12 }
13 
14-void test_get_unit(char* ustr, struct Unit* known_units, int known_units_len) {
15+void test_get_unit(char* ustr, struct Unit* known_units, int known_units_len, int stack_size) {
16 	int cap = 10;
17 	struct Unit *units = malloc(sizeof(struct Unit) * cap);
18 	int units_len = 0;
19 
20-	int vars_cap = 10;
21-	char *vars = malloc(MAX_STR_LEN * cap);
22+	int vars_cap = 0;
23+	char **vars = NULL;
24 	int vars_len = 0;
25 
26 	get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, ustr);
27@@ -58,6 +58,11 @@ void test_get_unit(char* ustr, struct Unit* known_units, int known_units_len) {
28 
29 	bool error = false;
30 
31+	if (vars_len != stack_size) {
32+		fprintf(stderr, "STACK assertion failed on test case \"%s\": %d != %d\n", ustr, vars_len, stack_size);
33+		error = true;
34+	}
35+
36 	for (int i = 0; i < units_len; i++) {
37 		if (units[i].type != known_units[i].type) {
38 			fprintf(stderr, "TYPE assertion failed on unit %d of test case \"%s\": %d != %d\n", i, ustr, units[i].type, known_units[i].type);
39@@ -70,7 +75,7 @@ void test_get_unit(char* ustr, struct Unit* known_units, int known_units_len) {
40 	}
41 	
42 	if (!error) {
43-		printf("\"%s\" parsed correctly\n", ustr);
44+		printf("\"%s\" parsed correctly with a stack of %d\n", ustr, vars_len);
45 	}
46 
47 	free(units);
48@@ -82,20 +87,34 @@ int main() {
49 	struct Unit *units = malloc(sizeof(struct Unit) * cap);
50 	int units_len = 0;
51 
52-	int vars_cap = 10;
53-	char *vars = malloc(MAX_STR_LEN * cap);
54+	int vars_cap = 0;
55+	char **vars = NULL;
56 	int vars_len = 0;
57 
58-	char* ustr = "((let(x 10px) set(x x * 2%) print(x)) (let(x 10px) set(x x * 2) print(x)))";
59+	char* ustr = "((let(x 10px) let(b 30px) set(x b * 2%) print(x)) (let(y 10px) set(y y * 2) print(y)))";
60 
61 	get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, ustr);
62 
63+	printf("Stack Size: %d\n", vars_len);
64+
65 	free(units);
66 	free(vars);
67 
68-	benchmark_get_unit(ustr);
69-
70-	test_get_unit("1 + 1", (struct Unit[]){{NUMBER, 1.0f}, {ADD, 0.0f}, {NUMBER, 1.0f}}, 3);
71-	test_get_unit("23px * 5678.7%", (struct Unit[]){{PX, 23.0f}, {MULT, 0.0f}, {PERCENT, 5678.7f}}, 3);
72-	test_get_unit("calc(23px * size)", (struct Unit[]){{CALC, 3}, {PX, 23.0f}, {MULT, 0.0f}, {VAR, -1.0f}}, 4);
73+	if (true) {
74+		benchmark_get_unit(ustr);
75+
76+		test_get_unit("1 + 1", (struct Unit[]){{NUMBER, 1.0f}, {ADD, 0.0f}, {NUMBER, 1.0f}}, 3, 0);
77+		test_get_unit("23px * 5678.7%", (struct Unit[]){{PX, 23.0f}, {MULT, 0.0f}, {PERCENT, 5678.7f}}, 3, 0);
78+		test_get_unit("calc(23px * size)", (struct Unit[]){{CALC, 3}, {PX, 23.0f}, {MULT, 0.0f}, {VAR, -1.0f}}, 4, 0);
79+		test_get_unit("((let(x 10px) set(x x * 2%) print(x)) (let(y 10px) set(y y * 2) print(y)))", (struct Unit[]){{GROUP, 22.0f}, 
80+			{GROUP, 10.0f}, 
81+				{LET, 2.0f}, {VAR, 0.0f}, {PX, 10.0f}, 
82+				{SET, 4.0f}, {VAR, 0.0f}, {VAR, 0.0f}, {MULT, 0.0f}, {PERCENT, 2.0f}, 
83+				{PRINT, 1.0f}, {VAR, 0.0f}, 
84+			{GROUP, 10.0f}, 
85+				{LET, 2.0f}, { VAR, 0.0f}, {PX, 10.0f}, 
86+				{SET, 4.0f}, {VAR, 0.0f}, {VAR, 0.0f}, {MULT, 0.0f}, {NUMBER, 2.0f}, 
87+				{PRINT, 1.0f}, {VAR, 0.0f}}
88+			, 23, 1);
89+	}
90 }
91diff --git a/src/parser.c b/src/parser.c
92index bfc901b..1f17515 100755
93--- a/src/parser.c
94+++ b/src/parser.c
95@@ -106,14 +106,6 @@ int write_var(char** vars_ptr, int* len, int* cap, char var[MAX_STR_LEN]) {
96 	return *len-1;
97 }
98 
99-/*
100-the goal is to make the stack clean so all vars are given a value for the stack that will be free at the reference of it and cleaned (overwritten) once done so this doesn't have to be managed at run time get_units will update the vars_len so unit_value knows how much to allocate.
101-VARS that point to lists will be made into LIST_PTR vars that point to the LIST on the heap, the LIST has the length of the LIST. the LIST_PTR still needs its scope to be managed
102-		No, no LIST_PTR, just a VAR location that will contain the LIST_PTR so if the LIST_PTR changes the VARS will always point to the right one
103-Lists will be managed somewhere else use the doubling of size for reallocs but keep the LIST value the real length
104-*/
105-
106-
107 void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* vars_len, int* vars_cap, char* value) {
108 	char buffer[MAX_STR_LEN];
109 	int buffer_len = 0;
110@@ -240,10 +232,15 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
111 
112 			write_unit(units, units_len, cap, placeholder);
113 			int before_count = *units_len;
114+			int before_vars_len = *vars_len;
115 
116 			get_unit(units, cap, units_len, vars, vars_len, vars_cap, args);
117 			free(args);
118 
119+			if (placeholder.type != LET) {
120+				vars_len = &before_vars_len;
121+			}
122+
123 			int child_count = *units_len - before_count;
124 
125 			// Reset the vars_len to remove any new vars created in the prevous scope
126@@ -359,8 +356,9 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
127 											unit.type = VAR;
128 
129 											bool var_found = false;
130+
131 											for (int j = *vars_len-1; j >= 0; j--) {
132-												if (strcmp(vars[j], buffer) == 0) {
133+												if (strcmp(&(*vars)[j * MAX_STR_LEN], buffer) == 0) {
134 													var_found = true;
135 													unit.value = j;
136 													break;