home readme diff tree note docs

0commit 1fd2817b9014b6fd852330814a252630426980de
1Author: lakefox <mason@lakefox.net>
2Date:   Sat Feb 21 20:51:53 2026 -0700
3
4    get_unit can return required size of stack
5
6diff --git a/include/grim.h b/include/grim.h
7index 28fb868..b746876 100755
8--- a/include/grim.h
9+++ b/include/grim.h
10@@ -7,8 +7,10 @@
11 
12 #define MAX_TOKENS 32
13 #define MAX_GROUPS 16
14-#define MAX_STR_LEN 128
15 #define MAX_ATTRS 16
16+#define MAX_TAGS 128
17+#define MAX_VARS 256
18+#define MAX_STR_LEN 128
19 
20 typedef enum {
21 	// Color
22@@ -118,45 +120,6 @@ struct Unit {
23 	float value;
24 };
25 
26-/*
27-typedef enum {
28-	All,
29-	Print,
30-	Screen,
31-	None,
32-	Hover,
33-	Fine,
34-	Coarse,
35-	Landscape,
36-	Portrait,
37-	Light,
38-	Dark,
39-	NoPreference,
40-	More,
41-	Less,
42-	Reduce,
43-	Fast,
44-	Slow
45-} Media;
46-
47-struct Range {
48-	size_t start;
49-	size_t end;
50-};
51-
52-struct Context {
53-	int id;
54-	size_t index;
55-	size_t length;
56-	Context* previous;
57-};
58-
59-struct Snapshot {
60-	Context* ctx;
61-	size_t pointer;
62-};
63-*/
64-
65 typedef struct {
66 	char key[MAX_STR_LEN];
67 	char value[MAX_STR_LEN];
68@@ -225,11 +188,6 @@ char* INNER_HTML(Node* node, char** buffer, size_t* size, int depth);
69 
70 void ADD_CLASS(Node* n, char* value);
71 
72-void get_unit(struct Unit** units, int* cap, int* unit_len, char* value);
73-
74-/*
75-bool testSelector(Node*, std::vector<std::vector<std::string>>);
76+void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* vars_len, int* vars_cap, char* value);
77 
78-Unit UnitValue(Memory&, std::vector<Unit>&, size_t, size_t);
79-*/
80 #endif // NODE_H
81diff --git a/playground/css_unit.c b/playground/css_unit.c
82index b60a590..cfe9a19 100644
83--- a/playground/css_unit.c
84+++ b/playground/css_unit.c
85@@ -8,7 +8,7 @@
86 #include "../include/grim.h"
87 #include "../include/parser.h"
88 
89-void benchmark_get_unit(SymbolTable* sym, char* value) {
90+void benchmark_get_unit(char* value) {
91 	struct timespec start, end;
92 
93 	int iterations = 10000;
94@@ -20,12 +20,17 @@ void benchmark_get_unit(SymbolTable* sym, char* value) {
95 	struct Unit *units = malloc(sizeof(struct Unit) * cap);
96 	int units_len = 0;
97 
98+	int vars_cap = 10;
99+	char *vars = malloc(MAX_STR_LEN * cap);
100+	int vars_len = 0;
101+
102 	for (int i = 0; i < iterations; i++) {
103 		units_len = 0;
104-		get_unit(sym, &units, &cap, &units_len, value);
105+		get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, value);
106 	}
107 
108 	free(units);
109+	free(vars);
110 
111 	// Get end time
112 	clock_gettime(CLOCK_MONOTONIC, &end);
113@@ -38,12 +43,15 @@ void benchmark_get_unit(SymbolTable* sym, char* value) {
114 }
115 
116 void test_get_unit(char* ustr, struct Unit* known_units, int known_units_len) {
117-	SymbolTable* sym = create_symbol_table(4096);
118 	int cap = 10;
119 	struct Unit *units = malloc(sizeof(struct Unit) * cap);
120 	int units_len = 0;
121 
122-	get_unit(sym, &units, &cap, &units_len, ustr);
123+	int vars_cap = 10;
124+	char *vars = malloc(MAX_STR_LEN * cap);
125+	int vars_len = 0;
126+
127+	get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, ustr);
128 
129 	
130 	assert(units_len == known_units_len);
131@@ -66,28 +74,28 @@ void test_get_unit(char* ustr, struct Unit* known_units, int known_units_len) {
132 	}
133 
134 	free(units);
135-
136-	FREE_SYMBOL_TABLE(sym);
137+	free(vars);
138 }
139 
140 int main() {
141-
142-	SymbolTable* sym = create_symbol_table(4096);
143 	int cap = 10;
144 	struct Unit *units = malloc(sizeof(struct Unit) * cap);
145 	int units_len = 0;
146 
147-	char* ustr = "1px + 200%";
148+	int vars_cap = 10;
149+	char *vars = malloc(MAX_STR_LEN * cap);
150+	int vars_len = 0;
151 
152-	get_unit(sym, &units, &cap, &units_len, ustr);
153+	char* ustr = "((let(x 10px) set(x x * 2%) print(x)) (let(x 10px) set(x x * 2) print(x)))";
154 
155-	free(units);
156+	get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, ustr);
157 
158-	benchmark_get_unit(sym, ustr);
159+	free(units);
160+	free(vars);
161 
162-	FREE_SYMBOL_TABLE(sym);
163+	benchmark_get_unit(ustr);
164 
165 	test_get_unit("1 + 1", (struct Unit[]){{NUMBER, 1.0f}, {ADD, 0.0f}, {NUMBER, 1.0f}}, 3);
166 	test_get_unit("23px * 5678.7%", (struct Unit[]){{PX, 23.0f}, {MULT, 0.0f}, {PERCENT, 5678.7f}}, 3);
167-	test_get_unit("calc(23px * size)", (struct Unit[]){{CALC, 3}, {PX, 23.0f}, {MULT, 0.0f}, {VAR, 0.0f}}, 4);
168+	test_get_unit("calc(23px * size)", (struct Unit[]){{CALC, 3}, {PX, 23.0f}, {MULT, 0.0f}, {VAR, -1.0f}}, 4);
169 }
170diff --git a/playground/syntax.wr b/playground/syntax.wr
171index 9f26bf2..0e75392 100644
172--- a/playground/syntax.wr
173+++ b/playground/syntax.wr
174@@ -111,5 +111,10 @@ Context -> width -> screen -> etc
175 	)))
176 
177 
178+	func(uppercase, (
179+		map(at(. 0), (set()))
180+	))
181+
182+
183 
184 )
185diff --git a/src/parser.c b/src/parser.c
186index b9c726f..bfc901b 100755
187--- a/src/parser.c
188+++ b/src/parser.c
189@@ -90,8 +90,32 @@ void write_unit(struct Unit** units_ptr, int* len, int* cap, struct Unit val) {
190 	(*len)++;
191 }
192 
193-void get_unit(struct Unit** units, int* cap, int* units_len, char* value) {
194-	char buffer[1024];
195+int write_var(char** vars_ptr, int* len, int* cap, char var[MAX_STR_LEN]) {
196+	if (*len >= *cap) {
197+		int new_cap = (*cap <= 0) ? 8 : (*cap * 2);
198+		char* next = realloc(*vars_ptr, MAX_STR_LEN * new_cap);
199+		if (!next) {
200+			fprintf(stderr, "Out of memory\n");
201+			exit(1);
202+		}
203+		*vars_ptr = next;
204+		*cap = new_cap;
205+	}
206+	strcpy(&(*vars_ptr)[*len * MAX_STR_LEN], var);
207+	(*len)++;
208+	return *len-1;
209+}
210+
211+/*
212+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.
213+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
214+		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
215+Lists will be managed somewhere else use the doubling of size for reallocs but keep the LIST value the real length
216+*/
217+
218+
219+void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* vars_len, int* vars_cap, char* value) {
220+	char buffer[MAX_STR_LEN];
221 	int buffer_len = 0;
222 
223 	char str_buffer[MAX_STR_LEN];
224@@ -107,9 +131,6 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char* value) {
225 
226 	int size = strlen(value);
227 
228-	
229-	int depth = 0; // Add every time a functions is entered in
230-
231 	for (int i = 0; i < size; i++) {
232 		char v = value[i];
233 		if (v == '\\' && !escaped) escaped = true;
234@@ -192,6 +213,7 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char* value) {
235 				} else {
236 					if (buffer[j] == '(') {
237 						nameset = true;
238+						name[name_len] = '\0';
239 					} else {
240 						name[name_len++] = buffer[j];
241 					}
242@@ -204,25 +226,33 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char* value) {
243 			// on LET add the word to the vars list
244 			// on SET reverse index the array
245 
246-			args[args_len++] = '\0';
247+			args[args_len] = '\0';
248 
249 			int function_idx = *units_len;
250-
251 			struct Unit placeholder = {0};
252-			write_unit(units, units_len, cap, placeholder);
253 
254+			if (name_len == 0) {
255+				placeholder.type = GROUP;
256+			} else {
257+				const struct FuncMap* fm = find_func(name, name_len);
258+				placeholder.type = fm->type;
259+			}
260+
261+			write_unit(units, units_len, cap, placeholder);
262 			int before_count = *units_len;
263-			get_unit(units, cap, units_len, args);
264+
265+			get_unit(units, cap, units_len, vars, vars_len, vars_cap, args);
266+			free(args);
267+
268 			int child_count = *units_len - before_count;
269 
270-			const struct FuncMap* fm = find_func(name, name_len);
271+			// Reset the vars_len to remove any new vars created in the prevous scope
272 			struct Unit final_unit;
273-			final_unit.type = fm ? fm->type : FUNC;
274+			final_unit.type = placeholder.type;
275 			final_unit.value = (float)child_count;
276 
277 			(*units)[function_idx] = final_unit;
278 
279-			free(args);
280 			buffer[0] = '\0';
281 			buffer_len = 0;
282 		} else if ((!inQuotes && (v == ',' ||  isspace(v))) || i >= size - 1) {
283@@ -230,15 +260,14 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char* value) {
284 				buffer[buffer_len++] = v;
285 			}
286 
287-			struct Unit unit;
288+			struct Unit unit = {0};
289 
290 			// Split by spaces into parts
291+			buffer[buffer_len] = '\0';
292 
293 			const struct MatchMap* mm = find_match(buffer, buffer_len);
294 			const struct ColorMap* cm = find_color(buffer, buffer_len);
295 
296-			buffer[buffer_len++] = '\0';
297-
298 			if (mm) { 
299 				//	Keyword Matching
300 				unit.type = mm->type;
301@@ -260,7 +289,7 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char* value) {
302 				
303 				for (size_t j = 0; j < suf_match_length; j++) {
304 					if (buffer_len >= sufMatch[j].trim+1) {
305-						if (strcmp(buffer + (buffer_len-sufMatch[j].trim-1), sufMatch[j].suffix) == 0) {
306+						if (strcmp(buffer + (buffer_len-sufMatch[j].trim), sufMatch[j].suffix) == 0) {
307 							found = true;
308 
309 							buffer[buffer_len-sufMatch[j].trim] = '\0';
310@@ -315,14 +344,36 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char* value) {
311 									// If we are here it is not a known parsable word, this could be a typo 
312 									// or a keyword like with the attr(size px) function. Here px would be
313 									// parsed but not size.
314+
315 									if (buffer_len > 0) {
316 										if (buffer[0] == ':') {
317 											unit.type = TAG;
318-											unit.value = intern_string(sym, buffer);
319+											
320+											int tag_value = 0;
321+											for (int j = 1; j < buffer_len; j++) {
322+												tag_value += buffer[j]*j;
323+											}
324 
325+											unit.value = tag_value;
326 										} else {
327 											unit.type = VAR;
328-											unit.value = intern_string(sym, buffer);
329+
330+											bool var_found = false;
331+											for (int j = *vars_len-1; j >= 0; j--) {
332+												if (strcmp(vars[j], buffer) == 0) {
333+													var_found = true;
334+													unit.value = j;
335+													break;
336+												}
337+											}
338+
339+											if (!var_found) {
340+												if (((*units_len)-1 >= 1) && (*units)[(*units_len)-1].type == LET) {
341+													unit.value = write_var(vars, vars_len, vars_cap, buffer);
342+												} else {
343+													unit.value = -1;
344+												}
345+											}
346 										}
347 									} else {
348 										continue;