feat: add and document user-defined functions!

This commit is contained in:
NunoSempere 2023-05-07 14:11:19 -04:00
parent f49b0fd2b4
commit 93696d97d4
3 changed files with 49 additions and 16 deletions

View File

@ -74,6 +74,12 @@ mumble> / a b c
mumble> VERBOSITY=0 mumble> VERBOSITY=0
mumble> VERBOSITY=1 mumble> VERBOSITY=1
mumble> VERBOSITY=2 mumble> VERBOSITY=2
mumble> def { {plus} {(@ {x y} {+ x y})} }
( )
mumble> plus
( @ { x y } { + x y } )
mumble> eval {plus 1 2}
3.000000
``` ```

BIN
mumble

Binary file not shown.

View File

@ -226,17 +226,17 @@ void delete_lispval(lispval* v)
if (VERBOSE) if (VERBOSE)
printfln("Freeing user-defined func"); printfln("Freeing user-defined func");
if (v->env != NULL) { if (v->env != NULL) {
destroy_lispenv(v->env); // destroy_lispenv(v->env);
free(v->env); free(v->env);
v->env = NULL; v->env = NULL;
} }
if (v->variables != NULL) { if (v->variables != NULL) {
delete_lispval(v->variables); // delete_lispval(v->variables);
free(v->variables); free(v->variables);
v->variables = NULL; v->variables = NULL;
} }
if (v->manipulation != NULL) { if (v->manipulation != NULL) {
delete_lispval(v->manipulation); // delete_lispval(v->manipulation);
free(v->manipulation); free(v->manipulation);
v->manipulation = NULL; v->manipulation = NULL;
} }
@ -334,6 +334,8 @@ lispval* get_from_lispenv(char* sym, lispenv* env)
if (env->parent != NULL) { if (env->parent != NULL) {
return get_from_lispenv(sym, env->parent); return get_from_lispenv(sym, env->parent);
} else { } else {
if (VERBOSE)
printfln("Unbound symbol %s", sym);
return lispval_err("Error: unbound symbol"); return lispval_err("Error: unbound symbol");
} }
// and this explains shadowing! // and this explains shadowing!
@ -460,6 +462,14 @@ lispval* read_lispval(mpc_ast_t* t)
} }
// Print // Print
void print_env(lispenv* env)
{
printfln("Environment: ");
for (int i = 0; i < env->count; i++) {
printfln("Value for symbol %s: ", env->syms[i]);
print_lispval_tree(env->vals[i], 2);
}
}
void print_lispval_tree(lispval* v, int indent_level) void print_lispval_tree(lispval* v, int indent_level)
{ {
char* indent = malloc(sizeof(char) * (indent_level + 1)); char* indent = malloc(sizeof(char) * (indent_level + 1));
@ -729,7 +739,7 @@ lispval* builtin_def(lispval* v, lispenv* env)
LISPVAL_ASSERT(source->type == LISPVAL_QEXPR, "Error: Argument passed to def is not a q-expr, i.e., a bracketed list."); LISPVAL_ASSERT(source->type == LISPVAL_QEXPR, "Error: Argument passed to def is not a q-expr, i.e., a bracketed list.");
LISPVAL_ASSERT(source->count == 2, "Error: Argument passed to def should be a q expr with two q expressions as children: def { { a b } { 1 2 } } "); LISPVAL_ASSERT(source->count == 2, "Error: Argument passed to def should be a q expr with two q expressions as children: def { { a b } { 1 2 } } ");
LISPVAL_ASSERT(source->cell[0]->type == LISPVAL_QEXPR, "Error: Argument passed to def should be a q expr with two q expressions as children: def { { a b } { 1 2 } } "); LISPVAL_ASSERT(source->cell[0]->type == LISPVAL_QEXPR, "Error: Argument passed to def should be a q expr with two q expressions as children: def { { a b } { 1 2 } } ");
LISPVAL_ASSERT(source->cell[1]->type == LISPVAL_QEXPR, "Error: Argument passed to def should be a q expr with two q expressions as children: def { { a b } { 1 2 } } "); LISPVAL_ASSERT(source->cell[1]->type == LISPVAL_QEXPR || source->cell[1]->type == LISPVAL_SEXPR, "Error: Argument passed to def should be a q expr with two q expressions as children: def { { a b } { 1 2 } } ");
LISPVAL_ASSERT(source->cell[0]->count == source->cell[1]->count, "Error: In function \"def\" both subarguments should have the same length"); LISPVAL_ASSERT(source->cell[0]->count == source->cell[1]->count, "Error: In function \"def\" both subarguments should have the same length");
lispval* symbols = source->cell[0]; lispval* symbols = source->cell[0];
@ -930,7 +940,7 @@ lispval* evaluate_lispval(lispval* l, lispenv* env)
// Check if the first element is an operation. // Check if the first element is an operation.
if (VERBOSE) if (VERBOSE)
printfln("Checking is first element is a function"); printfln("Checking if first element is a function");
if (l->count >= 2 && ((l->cell[0])->type == LISPVAL_BUILTIN_FUNC)) { if (l->count >= 2 && ((l->cell[0])->type == LISPVAL_BUILTIN_FUNC)) {
if (VERBOSE) if (VERBOSE)
@ -943,8 +953,10 @@ lispval* evaluate_lispval(lispval* l, lispenv* env)
// Ok, do this properly now. // Ok, do this properly now.
if (VERBOSE) if (VERBOSE)
printfln("Constructing function and operands"); printfln("Constructing function and operands");
lispval* f = clone_lispval(l->cell[0]); lispval* f = clone_lispval(l->cell[0]);
lispval* operands = lispval_sexpr(); lispval* operands = lispval_sexpr();
for (int i = 1; i < l->count; i++) { for (int i = 1; i < l->count; i++) {
lispval_append_child(operands, l->cell[i]); lispval_append_child(operands, l->cell[i]);
} }
@ -966,22 +978,37 @@ lispval* evaluate_lispval(lispval* l, lispenv* env)
} }
if (l->count >= 2 && ((l->cell[0])->type == LISPVAL_USER_FUNC)) { if (l->count >= 2 && ((l->cell[0])->type == LISPVAL_USER_FUNC)) {
// Do something with user-defined functions here if (VERBOSE)
printfln("Evaluating user-defined function");
lispval* f = clone_lispval(l->cell[0]); lispval* f = clone_lispval(l->cell[0]);
f->env->parent = env;
// check whether function takes as many arguments as given
LISPVAL_ASSERT(f->variables->count == (l->count - 1), "Error: Incorrect number of variables given to user-defined function"); LISPVAL_ASSERT(f->variables->count == (l->count - 1), "Error: Incorrect number of variables given to user-defined function");
if (VERBOSE)
printfln("Number of variables match");
for (int i = 1; i < l->count; i++) { if (VERBOSE) {
// lispval_append_child(operands, l->cell[i]); printfln("Function vars:");
insert_in_current_lispenv( print_lispval_tree(f->variables, 2);
f->variables->cell[i]->sym, l->cell[i], f->env); printfln("Function manipulation:");
print_lispval_tree(f->manipulation, 2);
} }
lispval* answer = evaluate_lispval(f->manipulation, f->env);
destroy_lispenv(f->env);
return answer;
// return lispval_err("Error: User-defined functions not yet implemented"); for (int i = 0; i < f->variables->count; i++) {
insert_in_current_lispenv(f->variables->cell[i]->sym, l->cell[i + 1], f->env);
}
if (VERBOSE) {
printfln("User defined function environment: ");
print_env(f->env);
}
lispval* temp = clone_lispval(f->manipulation);
temp->type = LISPVAL_SEXPR;
lispval* answer = evaluate_lispval(temp, f->env);
// lispval* answer = builtin_eval(f->manipulation, f->env);
// destroy_lispenv(f->env);
return answer;
return lispval_err("Error: User-defined functions not yet implemented");
} }
return l; return l;
@ -1099,7 +1126,7 @@ int main(int argc, char** argv)
} }
delete_lispval(answer); delete_lispval(answer);
if (VERBOSE > 1) if (VERBOSE > 1)
printfln("variable \"answer\" after deletion: %p", answer); printfln("variable \"answer\" after deletion: %p ", answer);
// delete_lispval(answer); // do this twice, just to see. // delete_lispval(answer); // do this twice, just to see.
//if(VERBOSE) printfln("Deleting this lispval:"); //if(VERBOSE) printfln("Deleting this lispval:");
// if(VERBOSE) print_lispval_tree(l,2); // if(VERBOSE) print_lispval_tree(l,2);