commit da339c2

uint  ·  2026-10-24 16:20:05 +0000 UTC
parent cf5e22d
Carry data pointer, implement public interface, add stupid birds example
2 files changed,  +104, -62
M expl.c
M expl.h
M expl.c
+102, -60
  1@@ -23,8 +23,8 @@ struct function {
  2 	expl_native native;
  3 	expl_node*  args;
  4 	expl_node*  body;
  5+	void*       data;
  6 };
  7-
  8 struct environment {
  9 	char*        name;
 10 	expl_value   value;
 11@@ -41,13 +41,14 @@ static int define(environment** env, const char* name, expl_value value);
 12 static expl_node* expression(parser* p);
 13 static expl_node* list(parser* p);
 14 static expl_value* lookup(environment* env, const char* name);
 15+expl_node* parse(const char* source);
 16 static expl_node* value(parser* p, expl_type type);
 17 
 18 static expl_value eval(expl_node* n, environment** env);
 19 static expl_value eval_call(expl_node* args, environment** env);
 20 static expl_value eval_fn(expl_node* args, environment** env);
 21 static expl_value eval_user(function* f, int argc, expl_value* argv, environment** env);
 22-static int register_native(environment** env, const char* name, expl_native fn);
 23+static int register_native(environment** env, const char* name, expl_native fn, void* data);
 24 
 25 static void skip_space(parser* p);
 26 static char* _strndup(const char* src, size_t len);
 27@@ -57,25 +58,6 @@ static expl_node* new_node(expl_type type);
 28 static void free_node(expl_node* node);
 29 static void free_environment(environment* env);
 30 
 31-static expl_value
 32-add(int argc, const expl_value* argv)
 33-{
 34-	expl_value result = { 0 };
 35-	expl_value fail = { 0 };
 36-	int i;
 37-
 38-	result.type = EXPL_VALUE_NUMBER;
 39-
 40-	for (i = 0; i < argc; i++) {
 41-		if (argv[i].type != EXPL_VALUE_NUMBER)
 42-			return fail;
 43-
 44-		result.as.number += argv[i].as.number;
 45-	}
 46-
 47-	return result;
 48-}
 49-
 50 static int
 51 define(environment** env, const char* name, expl_value value)
 52 {
 53@@ -164,6 +146,32 @@ lookup(environment* env, const char* name)
 54 	return NULL;
 55 }
 56 
 57+expl_node*
 58+parse(const char* source)
 59+{
 60+	parser p = { 0 };
 61+	expl_node* head = NULL;
 62+	expl_node** next = &head;
 63+
 64+	if (!source)
 65+		return NULL;
 66+	p.src = source;
 67+
 68+	skip_space(&p);
 69+	while (!current_char(&p, '\0')) {
 70+		*next = expression(&p);
 71+		if (!*next) {
 72+			free_node(head);
 73+			return NULL;
 74+		}
 75+
 76+		next = &(*next)->next;
 77+		skip_space(&p);
 78+	}
 79+
 80+	return head;
 81+}
 82+
 83 static expl_node*
 84 value(parser* p, expl_type type)
 85 {
 86@@ -295,7 +303,7 @@ eval_call(expl_node* n, environment** env)
 87 	/* call */
 88 	f = fn->as.function;
 89 	if (f->native)
 90-		result = f->native(argc, argv);
 91+		result = f->native(argc, argv, f->data);
 92 	else
 93 		result = eval_user(f, argc, argv, env);
 94 
 95@@ -367,7 +375,7 @@ eval_user(function* f, int argc, expl_value* argv, environment** env)
 96 }
 97 
 98 static int
 99-register_native(environment** env, const char* name, expl_native fn)
100+register_native(environment** env, const char* name, expl_native fn, void* data)
101 {
102 	function* f = malloc(sizeof(*f));
103 	expl_value value = { 0 };
104@@ -378,6 +386,7 @@ register_native(environment** env, const char* name, expl_native fn)
105 	f->native = fn;
106 	f->args = NULL;
107 	f->body = NULL;
108+	f->data = data;
109 
110 	value.type = EXPL_VALUE_FUNCTION;
111 	value.as.function = f;
112@@ -493,36 +502,57 @@ free_environment(environment* env)
113 	}
114 }
115 
116-expl* expl_init(void);
117-void expl_close(expl* ctx);
118-int expl_register(expl* ctx, const char* name, expl_native fn);
119-expl_value expl_run(expl* ctx, const char* source);
120-void expl_print(const expl_node* node, int depth);
121+expl* expl_init(void)
122+{
123+	return calloc(1, sizeof(expl));
124+}
125 
126-expl_node*
127-expl_parse(const char* source)
128+void expl_close(expl* ctx)
129 {
130-	parser p = { 0 };
131-	expl_node* head = NULL;
132-	expl_node** next = &head;
133+	if (!ctx)
134+		return;
135 
136-	if (!source)
137-		return NULL;
138-	p.src = source;
139+	free_environment(ctx->env);
140+	free_node(ctx->programs);
141+	free(ctx);
142+}
143 
144-	skip_space(&p);
145-	while (!current_char(&p, '\0')) {
146-		*next = expression(&p);
147-		if (!*next) {
148-			free_node(head);
149-			return NULL;
150-		}
151+int
152+expl_register(expl* ctx, const char* name, expl_native fn, void* data)
153+{
154+	if (!ctx || !name || !fn)
155+		return 0;
156 
157-		next = &(*next)->next;
158-		skip_space(&p);
159+	return register_native(&ctx->env, name, fn, data);
160+}
161+
162+expl_value
163+expl_run(expl* ctx, const char* source)
164+{
165+	expl_value result = { 0 };
166+	expl_node* program = NULL;
167+	expl_node* n = NULL;
168+
169+	if (!ctx || !source)
170+		return result;
171+
172+	program = parse(source);
173+	if (!program)
174+		return result;
175+
176+	for (n = program; n; n = n->next)
177+		result = eval(n, &ctx->env);
178+
179+	if (ctx->programs) {
180+		n = ctx->programs;
181+		while (n->next)
182+			n = n->next;
183+		n->next = program;
184 	}
185+	else
186+		ctx->programs = program;
187 
188-	return head;
189+	return result;
190 }
191 
192 void
193@@ -554,27 +584,39 @@ expl_print(const expl_node* node, int depth)
194 }
195 
196 #if 1
197-int
198-main(void)
199+static expl_value
200+birds_who_hit_my_window(int argc, const expl_value* argv, void* data)
201 {
202-	environment* env = NULL;
203-	expl_node* program = NULL;
204-	expl_node* n = NULL;
205+	int* count = (int*)data;
206 	expl_value result = { 0 };
207 
208-	if (!register_native(&env, "+", add))
209-		return EXIT_FAILURE;
210+	if (argc == 1 && argv[0].type == EXPL_VALUE_NUMBER)
211+		*count += (int)argv[0].as.number;
212 
213-	program = expl_parse(
214-		"(fn add (x y) (+ x y))\n"
215-		"(add 10 20)"
216-	);
217+	result.type = EXPL_VALUE_NUMBER;
218+	result.as.number = *count;
219 
220-	for (n = program; n; n = n->next)
221-		result = eval(n, &env);
222+	return result;
223+}
224+
225+#define FIND_THE_BIRDS \
226+"(fn foo (x) (birds_who_hit_window x))\n" \
227+"(foo 134)\n"
228+
229+int
230+main(void)
231+{
232+	int birds_who_hit_my_window_c = 0;
233+	expl* ctx = expl_init();
234+
235+	if (!ctx)
236+		return EXIT_FAILURE;
237 
238-	printf("%g\n", result.as.number);
239+	expl_register(ctx, "birds_who_hit_my_window", birds_who_hit_my_window, &birds_who_hit_my_window_c);
240+	expl_run(ctx, FIND_THE_BIRDS);
241+	printf("Stupid birds: %d\n", birds_who_hit_my_window_c);
242 
243+	expl_close(ctx);
244 	return EXIT_SUCCESS;
245 }
246 #endif
M expl.h
+2, -2
 1@@ -37,7 +37,7 @@ typedef struct expl_node expl_node;
 2 typedef struct expl_value expl_value;
 3 typedef struct expl expl;
 4 
 5-typedef expl_value (*expl_native)(int argc, const expl_value* argv);
 6+typedef expl_value (*expl_native)(int argc, const expl_value* argv, void* data);
 7 
 8 struct expl_node {
 9 	char*      value;
10@@ -57,7 +57,7 @@ struct expl_value {
11 
12 expl* expl_init(void);
13 void expl_close(expl* ctx);
14-int expl_register(expl* ctx, const char* name, expl_native fn);
15+int expl_register(expl* ctx, const char* name, expl_native fn, void* data);
16 expl_value expl_run(expl* ctx, const char* source);
17 void expl_print(const expl_node* node, int depth);
18