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;