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;