commit cf5e22d

uint  ·  2026-10-24 16:04:47 +0000 UTC
parent cec99cb
Evaluate user defined functions, add expl context struct
2 files changed,  +138, -13
M expl.c
M expl.h
M expl.c
+133, -12
  1@@ -14,6 +14,11 @@ typedef struct function function;
  2 typedef struct environment environment;
  3 typedef struct parser parser;
  4 
  5+struct expl {
  6+	environment* env;
  7+	expl_node*   programs;
  8+};
  9+
 10 struct function {
 11 	expl_native native;
 12 	expl_node*  args;
 13@@ -40,6 +45,8 @@ static expl_node* value(parser* p, expl_type type);
 14 
 15 static expl_value eval(expl_node* n, environment** env);
 16 static expl_value eval_call(expl_node* args, environment** env);
 17+static expl_value eval_fn(expl_node* args, environment** env);
 18+static expl_value eval_user(function* f, int argc, expl_value* argv, environment** env);
 19 static int register_native(environment** env, const char* name, expl_native fn);
 20 
 21 static void skip_space(parser* p);
 22@@ -50,6 +57,25 @@ static expl_node* new_node(expl_type type);
 23 static void free_node(expl_node* node);
 24 static void free_environment(environment* env);
 25 
 26+static expl_value
 27+add(int argc, const expl_value* argv)
 28+{
 29+	expl_value result = { 0 };
 30+	expl_value fail = { 0 };
 31+	int i;
 32+
 33+	result.type = EXPL_VALUE_NUMBER;
 34+
 35+	for (i = 0; i < argc; i++) {
 36+		if (argv[i].type != EXPL_VALUE_NUMBER)
 37+			return fail;
 38+
 39+		result.as.number += argv[i].as.number;
 40+	}
 41+
 42+	return result;
 43+}
 44+
 45 static int
 46 define(environment** env, const char* name, expl_value value)
 47 {
 48@@ -237,35 +263,109 @@ eval_call(expl_node* n, environment** env)
 49 	expl_value* fn = NULL;
 50 	expl_value* argv = NULL;
 51 	expl_node* arg = NULL;
 52+	function* f = NULL;
 53 	int argc = 0;
 54+	int i = 0;
 55 
 56 	if (!n->child || n->child->type != EXPL_TYPE_ATOM)
 57 		return result;
 58+	
 59+	/* defined function */
 60+	if (!strcmp(n->child->value, "fn"))
 61+		return eval_fn(n->child->next, env);	
 62 
 63 	fn = lookup(*env, n->child->value);
 64 	if (!fn || fn->type != EXPL_VALUE_FUNCTION)
 65 		return result;
 66 
 67-	/* count args */
 68 	for (arg = n->child->next; arg; arg = arg->next)
 69 		argc++;
 70 
 71-	argv = argc ? malloc(argc * sizeof(*argv)) : NULL;
 72-	if (argc && !argv)
 73-		return result;
 74+	/* allocate argv */
 75+	if (argc) {
 76+		argv = malloc(argc * sizeof(*argv));
 77+		if (!argv)
 78+			return result;
 79+	}
 80 
 81-	argc = 0;
 82+	/* evaluate arguments */
 83 	for (arg = n->child->next; arg; arg = arg->next)
 84-		argv[argc++] = eval(arg, env);
 85+		argv[i++] = eval(arg, env);
 86 
 87-	/* call native fn if it exists */
 88-	if (((function*)fn->as.function)->native)
 89-		result = ((function*)fn->as.function)->native(argc, argv);
 90+	/* call */
 91+	f = fn->as.function;
 92+	if (f->native)
 93+		result = f->native(argc, argv);
 94+	else
 95+		result = eval_user(f, argc, argv, env);
 96 
 97 	free(argv);
 98 	return result;
 99 }
100 
101+static expl_value
102+eval_fn(expl_node* args, environment** env)
103+{
104+	expl_value result = { 0 };
105+	expl_node* name = NULL;
106+	function* f = NULL;
107+
108+	name = args;
109+	if (!name || name->type != EXPL_TYPE_ATOM ||
110+	    !name->next || !name->next->next ||
111+	    name->next->type != EXPL_TYPE_LIST)
112+		return result;
113+
114+	f = malloc(sizeof(*f));
115+	if (!f)
116+		return result;
117+
118+	f->native = NULL;
119+	f->args = name->next->child;
120+	f->body = name->next->next;
121+
122+	result.type = EXPL_VALUE_FUNCTION;
123+	result.as.function = f;
124+
125+	if (!define(env, name->value, result)) {
126+		free(f);
127+		result.type = EXPL_VALUE_NIL;
128+	}
129+
130+	return result;
131+}
132+
133+static expl_value
134+eval_user(function* f, int argc, expl_value* argv, environment** env)
135+{
136+	environment* local = *env;
137+	expl_node* param = f->args;
138+	environment* next = NULL;
139+	expl_node* body = NULL;
140+	expl_value result = { 0 };
141+	int i;
142+
143+	for (i = 0; i < argc && param; i++) {
144+		if (!define(&local, param->value, argv[i]))
145+			break;
146+		param = param->next;
147+	}
148+
149+	if (i == argc && !param) {
150+		for (body = f->body; body; body = body->next)
151+			result = eval(body, &local);
152+	}
153+
154+	while (local != *env) {
155+		next = local->next;
156+		free(local->name);
157+		free(local);
158+		local = next;
159+	}
160+
161+	return result;
162+}
163+
164 static int
165 register_native(environment** env, const char* name, expl_native fn)
166 {
167@@ -393,6 +493,12 @@ free_environment(environment* env)
168 	}
169 }
170 
171+expl* expl_init(void);
172+void expl_close(expl* ctx);
173+int expl_register(expl* ctx, const char* name, expl_native fn);
174+expl_value expl_run(expl* ctx, const char* source);
175+void expl_print(const expl_node* node, int depth);
176+
177 expl_node*
178 expl_parse(const char* source)
179 {
180@@ -451,9 +557,24 @@ expl_print(const expl_node* node, int depth)
181 int
182 main(void)
183 {
184-	expl_node* node = expl_parse("(fn square (x \"hi\") (* x x))");
185-	expl_print(node, 0);
186-	free_node(node);
187+	environment* env = NULL;
188+	expl_node* program = NULL;
189+	expl_node* n = NULL;
190+	expl_value result = { 0 };
191+
192+	if (!register_native(&env, "+", add))
193+		return EXIT_FAILURE;
194+
195+	program = expl_parse(
196+		"(fn add (x y) (+ x y))\n"
197+		"(add 10 20)"
198+	);
199+
200+	for (n = program; n; n = n->next)
201+		result = eval(n, &env);
202+
203+	printf("%g\n", result.as.number);
204+
205 	return EXIT_SUCCESS;
206 }
207 #endif
M expl.h
+5, -1
 1@@ -35,6 +35,7 @@ typedef enum {
 2 
 3 typedef struct expl_node expl_node;
 4 typedef struct expl_value expl_value;
 5+typedef struct expl expl;
 6 
 7 typedef expl_value (*expl_native)(int argc, const expl_value* argv);
 8 
 9@@ -54,8 +55,11 @@ struct expl_value {
10 	} as;
11 };
12 
13+expl* expl_init(void);
14+void expl_close(expl* ctx);
15+int expl_register(expl* ctx, const char* name, expl_native fn);
16+expl_value expl_run(expl* ctx, const char* source);
17 void expl_print(const expl_node* node, int depth);
18-expl_node* expl_parse(const char* source);
19 
20 #endif /* EXPL_H */
21