home readme diff tree note docs

0commit 8d62ad7566558c937bf0ec832d7d2ee71a6f9ade
1Author: lakefox <mason@lakefox.net>
2Date:   Mon Apr 6 09:52:31 2026 -0600
3
4    While, range, range as
5
6diff --git a/Makefile b/Makefile
7index c9a7370..b3d0445 100755
8--- a/Makefile
9+++ b/Makefile
10@@ -57,12 +57,12 @@ GDB_FLAGS ?=
11 debug_css_units:
12 	@clear
13 	make run_css_unit_playground
14-	gdb $(GDB_FLAGS) -ex "b 146" -ex "run" -ex "print *units@units_len" build/css_unit_playground
15+	gdb $(GDB_FLAGS) -ex "b 147" -ex "run" -ex "print *units@units_len" build/css_unit_playground
16 
17 debug_unit_debug:
18 	@clear
19 	make run_unit_value_playground
20-	gdb $(GDB_FLAGS) -ex "b 146" -ex "run" -ex "print *units@units_len" build/unit_value_playground
21+	gdb $(GDB_FLAGS) -ex "b 147" -ex "run" -ex "print *units@units_len" build/unit_value_playground
22 
23 
24 quiet_%: GDB_FLAGS = --batch
25diff --git a/include/grim.h b/include/grim.h
26index 7db3a5d..b14402e 100755
27--- a/include/grim.h
28+++ b/include/grim.h
29@@ -79,7 +79,7 @@ typedef enum {
30 		NEAREST, UP, DOWN, TO_ZERO,	
31 
32 	// Keyword
33-		SCREEN, TOKEN, NO_SUPPORT, IMAGE, BOOL, VAR, PTR, TAG, CHAR, JUMP, FREE, REG, ARG,
34+		SCREEN, TOKEN, NO_SUPPORT, IMAGE, BOOL, VAR, PTR, TAG, CHAR, JUMP, FREE, REG, ARG, AS,
35 
36 	FUNC_START,
37 		// General Functions
38diff --git a/maps/match.gperf b/maps/match.gperf
39index c8a69d9..d959404 100644
40--- a/maps/match.gperf
41+++ b/maps/match.gperf
42@@ -145,4 +145,5 @@ nearest, NEAREST
43 up, UP
44 down, DOWN
45 to-zero, TO_ZERO
46+as, AS
47 %%
48diff --git a/playground/css_unit.c b/playground/css_unit.c
49index 832de62..1a15211 100644
50--- a/playground/css_unit.c
51+++ b/playground/css_unit.c
52@@ -73,6 +73,8 @@ void test_get_unit(char* ustr, struct Unit* known_units, int known_units_len, in
53 
54 	get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, &funcs, &funcs_len, &funcs_cap, &stack_len, &max_register_size, ustr);
55 
56+	printf("-------------- CASE ----------------\n");
57+
58 	bool error = false;
59 	if (units_len != known_units_len) {
60 		printf("| \n");
61@@ -139,7 +141,7 @@ int main() {
62 	int stack_len = 0;
63 	int max_register_size = 0;
64 
65-	char* ustr = "let(i 0) while((i < 90) set(i (i + 1))) print(i)";
66+	char* ustr = "let(a 0) while(range(1000000 as b) (set(a (a + b)))) print(a)";
67 
68 	get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, &funcs, &funcs_len, &funcs_cap, &stack_len, &max_register_size, ustr);
69 
70@@ -166,11 +168,11 @@ int main() {
71 		);
72 		test_get_unit("calc(23px * size)",
73 			(struct Unit[]){{PX, 23}, {VAR, 0}, {MULT, 2}, {CALC, 1}},
74-			4, 1, 2
75+			4, 0, 3
76 		);
77 		test_get_unit("(let(x 10px) set(x 30px) (let(x 50px) print(x)) print(x))", 
78 			(struct Unit[]){{PTR, 0}, {PX, 10}, {LET, 2}, {PTR, 0}, {PX, 30}, {SET, 2}, {PTR, 1}, {PX, 50}, {LET, 2}, {VAR, 1}, {PRINT, 1}, {GROUP, 2}, {VAR, 0}, {PRINT, 1}, {GROUP, 4}}, 
79-			15, 2, 4
80+			15, 2, 14
81 		);
82 		test_get_unit("((let(x 10px) set(x x * 2%) print(x)) (let(y 10px) set(y y * 2) print(y)))", (struct Unit[]){ 
83 				{PTR, 0}, {PX, 10}, {LET, 2},
84@@ -182,28 +184,28 @@ int main() {
85 				{VAR, 0}, {PRINT, 1},
86 			{GROUP, 3}, 
87 		{GROUP, 2}}
88-			, 23, 1, 3);
89+			, 23, 1, 22);
90 		test_get_unit("(let(x :name \"john doe\" :age 27))", 
91 			(struct Unit[]){{PTR, 0}, {TAG, 1035}, {CHAR, 106}, {CHAR, 111}, {CHAR, 104}, {CHAR, 110}, {CHAR, 32}, {CHAR, 100}, {CHAR, 111}, {CHAR, 101}, {TAG, 606}, {NUMBER, 27}, {LET, 12}, {GROUP, 1}}, 
92-			14, 1, 12
93+			14, 1, 13
94 		);
95 		test_get_unit("(if((style(--scheme) == dark) calc(#eeeeee == '1')))", 
96 			(struct Unit[]){{VAR, 0}, {CUSTOM_FUNCS, 1}, {VAR, 0}, {EQ, 2}, {GROUP, 1}, {IF, 6}, {HEX, 2.19425599e-38}, {CHAR, 49}, {EQ, 2}, {CALC, 1}, {GROUP, 1}}, 
97-			11, 1, 2
98+			11, 0, 10
99 		);
100 
101 		test_get_unit("(if((style(--scheme) == dark) calc(#eeeeee == '1') print(123)))", 
102 			(struct Unit[]){{VAR, 0}, {CUSTOM_FUNCS, 1}, {VAR, 0}, {EQ, 2}, {GROUP, 1}, {IF, 6}, {HEX, 2.19425599e-38}, {CHAR, 49}, {EQ, 2}, {CALC, 1}, {JUMP, 3}, {NUMBER, 123}, {PRINT, 1}, {GROUP, 3}}, 
103-			14, 1, 3
104+			14, 0, 13
105 		);
106 
107 		test_get_unit("(if((style(--scheme) == dark) calc(#eeeeee == calc(123)) print(123)))", 
108 			(struct Unit[]){{VAR, 0}, {CUSTOM_FUNCS, 1}, {VAR, 0}, {EQ, 2}, {GROUP, 1}, {IF, 7}, {HEX, 2.19425599e-38}, {NUMBER, 123}, {CALC, 1}, {EQ, 2}, {CALC, 1}, {JUMP, 3}, {NUMBER, 123}, {PRINT, 1}, {GROUP, 3}}, 
109-			15, 1, 3
110+			15, 0, 14
111 		);
112 		test_get_unit("let(height 10) def(x (name age) print(name age height 1 2 3)) x(1 1)", 
113 			(struct Unit[]){{PTR, 0}, {NUMBER, 10}, {LET, 2}, {DEF, 11}, {REG, 0}, {REG, 1}, {VAR, 0}, {NUMBER, 1}, {NUMBER, 2}, {NUMBER, 3}, {PRINT, 6}, {JUMP, 2}, {NUMBER, 1}, {NUMBER, 1}, {CUSTOM_FUNCS+4, 2}}, 
114-			15, 3, 6
115+			15, 1, 14
116 		);
117 
118 	}
119diff --git a/playground/syntax.wr b/playground/syntax.wr
120index 1c6b2de..f18b996 100644
121--- a/playground/syntax.wr
122+++ b/playground/syntax.wr
123@@ -70,9 +70,9 @@ Context -> width -> screen -> etc
124 	for(each(x) (print(.)))
125 
126 
127-	// Elements are made and/or accessed with queryselectors
128-	// if no relationship is given then it won't be inserted
129-	// either way the a ref to the element is always returned
130+	-- Elements are made and/or accessed with queryselectors
131+	-- if no relationship is given then it won't be inserted
132+	-- either way the a ref to the element is always returned
133 	$(body>modal (
134 		:click ((e) (
135 			:text ("You clicked me " x "times")
136@@ -209,7 +209,6 @@ Context -> width -> screen -> etc
137 		</person>`
138 	)
139 
140-	let(p1 x(name("John") age(12) first_or_last("first")))
141 	let(p2 x("Mary" 99 "first"))
142 
143 	let(people p1)
144@@ -222,6 +221,15 @@ Context -> width -> screen -> etc
145 		map(value ($1 + 60))
146 	))
147 
148-	print(uppercase(value("test")))
149+	-- Test comment
150+	-- print(uppercase(value("test")))
151+
152+	===
153+	This is a multiline comment
154+
155+	while(range(0 10 5 as i) (
156+		print(at(x i))
157+	))
158+	===
159 
160 )
161diff --git a/playground/unit_value.c b/playground/unit_value.c
162index 067b7eb..2511be7 100644
163--- a/playground/unit_value.c
164+++ b/playground/unit_value.c
165@@ -145,7 +145,7 @@ int main() {
166 	int stack_len = 0;
167 	int max_register_size = 0;
168 
169-	char* ustr = "let(i 0) while(true (print(i < 10, i) set(i (i + 1))))";
170+	char* ustr = "let(a 0) while(range(1000000) (set(a (a + 1)))) a";
171 
172 	get_unit(&units, &cap, &units_len, &vars, &vars_len, &vars_cap, &funcs, &funcs_len, &funcs_cap, &stack_len, &max_register_size, ustr);
173 
174@@ -177,7 +177,7 @@ int main() {
175 
176 
177 	if (true) {
178-		//benchmark_unit_value(ustr);
179+	//	benchmark_unit_value(ustr);
180 
181 		test_unit_value("1 + 1", 2);
182 		test_unit_value("pow(10 2)", 100);
183@@ -199,6 +199,8 @@ int main() {
184 		test_unit_value("let(height 10) def(x (age name) (age + height * name)) x(4 x(5 x(6 x(7 8))))", 456960);
185 		test_unit_value("let(height 10) def(x () (21 + 3)) x()", 24);
186 		test_unit_value("let(height 10) def(x (name age) (age + height * name)) x(4 x(5 x(6 x(7 8))))", 16560);
187+		test_unit_value("let(a 0) while(range(1000000 as b) (set(a (b)))) a", 1000000);
188+		test_unit_value("let(a 0) while(range(1000000) (set(a (a + 1)))) a", 1000000);
189 
190 		// cases for all rel units and every function
191 	}
192diff --git a/src/grim.c b/src/grim.c
193index 67b29a4..02823fe 100755
194--- a/src/grim.c
195+++ b/src/grim.c
196@@ -809,23 +809,29 @@ float unit_value(struct Slot stack[], int register_size, struct Unit* units, int
197 			}
198 			case PRINT: {
199 				printf("> ");
200+				bool last_char = false;
201 				for (int j = idx; j < idx+(int)unit.value; j++) {
202 					if (registers[j].type == CHAR) {
203 						printf("%c", (char)registers[j].value);
204-					} else if (registers[j].type == BOOL) {
205-						if (registers[j].value == 0) {
206-							printf("false ");
207+						last_char = true;
208+					} else {
209+						printf(" ");
210+						last_char = false;
211+						if (registers[j].type == BOOL) {
212+							if (registers[j].value == 0) {
213+								printf("false ");
214+							} else {
215+								printf("true ");
216+							}
217+						} else if (registers[j].type == HEX) {
218+							uint32_t u32;
219+							char hex[11];
220+							memcpy(&u32, &registers[j].value, sizeof(u32));
221+							sprintf(hex, "0x%08x", u32);
222+							printf("%s ", hex);
223 						} else {
224-							printf("true ");
225+							printf("%f ", registers[j].value);
226 						}
227-					} else if (registers[j].type == HEX) {
228-						uint32_t u32;
229-						char hex[11];
230-						memcpy(&u32, &registers[j].value, sizeof(u32));
231-						sprintf(hex, "0x%08x", u32);
232-						printf("%s ", hex);
233-					} else {
234-						printf("%f ", registers[j].value);
235 					}
236 				}
237 				printf("\n");
238@@ -956,6 +962,19 @@ float unit_value(struct Slot stack[], int register_size, struct Unit* units, int
239 				register_len = idx + 1;
240 				break;
241 			}
242+			case RANGE: {
243+				if (units[i-3].value < units[i-2].value) {
244+					units[i-3].value += units[i-1].value;
245+					registers[idx].type = BOOL;
246+					registers[idx].value = 1;
247+				} else {
248+					registers[idx].type = BOOL;
249+					registers[idx].value = 0;
250+					units[i-3].value = units[i-4].value;
251+				}
252+				register_len = idx+1;
253+				break;
254+			}
255 			case ADD:
256 				registers[idx].type = NUMBER;
257 				registers[idx].value += registers[idx+1].value;
258diff --git a/src/parser.c b/src/parser.c
259index 3560c76..14bf694 100755
260--- a/src/parser.c
261+++ b/src/parser.c
262@@ -187,7 +187,7 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
263 		}
264 
265 		if (i+1 < size) {
266-			if (v == '/' && value[i+1] == '/') {
267+			if (v == '-' && value[i+1] == '-') {
268 				inlineComment = true;
269 				continue;
270 			}
271@@ -199,16 +199,18 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
272 				continue;
273 			}
274 
275-			if (v == '/' && value[i+1] == '*') {
276-				multilineComment = true;
277-			}
278+			if (i + 2 < size) {
279+				if (v == '=' && value[i+1] == '=' && value[i+2] == '=') {
280+					multilineComment = true;
281+				}
282 
283-			if (multilineComment) {
284-				if (v == '*' && value[i+1] == '/') {
285-					i++;
286-					multilineComment = false;
287+				if (multilineComment) {
288+					if (v == '=' && value[i+1] == '=' && value[i+2] == '=') {
289+						i++;
290+						multilineComment = false;
291+					}
292+					continue;
293 				}
294-				continue;
295 			}
296 		}
297 
298@@ -353,7 +355,7 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
299 				} else if (child_count == 3) {
300 					// if else
301 					// Move back 1 and add a jump at the end of the conditional logic
302-					if ((unsigned long)(*cap) < (indexes[2] + 23) * sizeof(struct Unit)) {
303+					if ((unsigned long)(*cap) < (indexes[2]) * sizeof(struct Unit)) {
304 						*units = realloc(*units, sizeof(struct Unit) * (*cap * 2));
305 					}
306 
307@@ -393,13 +395,97 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
308 					*units = realloc(*units, sizeof(struct Unit) * (*cap * 2));
309 				}
310 
311-				memmove((*units) + indexes[0], (*units) + indexes[0] - 1, (*units_len - indexes[0]) * sizeof(struct Unit));
312-				(*units)[indexes[0]].type = IF;
313-				(*units)[indexes[0]].value = (*units_len-indexes[0]);
314-				(*units)[*units_len].type = JUMP;
315-				(*units)[*units_len].value = before_count-1;
316-				*units_len += 1;
317+				if ((*units)[indexes[0]-1].type == RANGE && (*units)[indexes[0]-2].type == REG) {
318+					// Need to remove the REG and replace all of the REG REFS with the correct value
319+					struct Unit reg = (*units)[indexes[0]-2];
320+					memmove((*units) + indexes[0] - 2, (*units) + indexes[0] - 1, (*units_len - indexes[0]) * sizeof(struct Unit));
321+					memmove((*units) + indexes[0], (*units) + indexes[0] - 1, (*units_len - indexes[0]) * sizeof(struct Unit));
322+					(*units)[indexes[0] - 2].value = 4; // We just wrote over the REG so update RANGE to 4
323 
324+					(*units)[indexes[0] - 1].type = IF;
325+					(*units)[indexes[0] - 1].value = (*units_len-indexes[0]);
326+					(*units)[*units_len-1].type = JUMP;
327+					if (before_count > 0) {
328+						(*units)[*units_len-1].value = before_count; // +1 because the RANGE has a reset value at pos 0
329+					} else {
330+						(*units)[*units_len-1].value = 1;
331+					}
332+					
333+					// Replace all REG with the correct position
334+					for (int j = indexes[0]; j < *units_len; j++) {
335+						if ((*units)[j].type == REG && (*units)[j].value == reg.value) {
336+							(*units)[j].value = before_count+1; // the second value in the chunk
337+						}
338+					}
339+				} else {
340+					memmove((*units) + indexes[0], (*units) + indexes[0] - 1, (*units_len - indexes[0]) * sizeof(struct Unit));
341+					
342+					(*units)[indexes[0]].type = IF;
343+					(*units)[indexes[0]].value = (*units_len-indexes[0]);
344+					(*units)[*units_len].type = JUMP;
345+					if (before_count > 0) {
346+						(*units)[*units_len].value = before_count-1;
347+					} else {
348+						(*units)[*units_len].value = 0;
349+					}
350+					*units_len += 1;
351+				}
352+			} else if (placeholder.type == RANGE) {
353+				if (sizeof(units) / sizeof(struct Unit) < ((*units_len)+3) * sizeof(struct Unit)) {
354+					*units = realloc(*units, sizeof(struct Unit) * (*cap * 2));
355+				}
356+				bool has_as = false;
357+				int as_pos = 0;
358+				struct Unit as;
359+				for (int j = before_count; j < *units_len; j++) {
360+					if ((*units)[j].type == AS) {
361+						has_as = true;
362+						as_pos = j;
363+						as = (*units)[j + 1];
364+						break;
365+					}
366+				}
367+
368+				if (!has_as) {
369+					as_pos = placeholder.value;
370+				}
371+
372+				int count = as_pos-before_count;
373+				int start = (*units_len - 1)-placeholder.value; // -1 because *units_len stores next postition
374+
375+				struct Unit range = (*units)[*units_len-1];
376+				struct Unit start_value = (*units)[before_count];
377+				struct Unit end_value = (*units)[before_count + 1];
378+				struct Unit inc_value = (*units)[before_count + 2];
379+
380+				if (count < 2) { 
381+					// Add a starting value of 0
382+					end_value = start_value;
383+					start_value.type = NUMBER;
384+					start_value.value = 0;
385+					*units_len += 1;
386+				}
387+				if (count < 3) {
388+					// Add a step of 1
389+					inc_value.type = NUMBER;
390+					inc_value.value = 1;
391+					*units_len += 1;
392+				}
393+
394+				(*units)[before_count] = start_value;
395+				(*units)[before_count + 1] = start_value;
396+				(*units)[before_count + 2] = end_value;
397+				(*units)[before_count + 3] = inc_value;
398+
399+				if (has_as) {
400+					(*units)[before_count + 4] = as;
401+					(*units)[before_count + 5] = range;
402+					(*units)[before_count + 5].value = 5;
403+				} else {
404+					*units_len += 1;
405+					(*units)[before_count + 4] = range;
406+					(*units)[before_count + 4].value = 4;
407+				}
408 			}
409 
410 			if (hasOP) {
411@@ -533,11 +619,12 @@ void get_unit(struct Unit** units, int* cap, int* units_len, char** vars, int* v
412 												if (!var_found) {
413 													unit.type = REG;
414 													int tag_value = 0;
415-													for (int j = 1; j < buffer_len; j++) {
416-														tag_value += buffer[j]*j;
417+													for (int j = 0; j < buffer_len; j++) {
418+														tag_value += buffer[j]*(j+1);
419 													}
420 
421-													unit.value = tag_value;												}
422+													unit.value = tag_value;
423+												}
424 											}
425 										}
426 									} else {