From 3bb0ec5e0017c3c24bd70234a1e55e98568a0ff2 Mon Sep 17 00:00:00 2001
From: Elijah Cohen <eli@eli173.com>
Date: Mon, 12 Aug 2024 00:52:02 -0500
Subject: [PATCH] made dubious changes to eval structure

---
 ideas.org                 |  6 +++
 src/builtins.c            |  6 +--
 src/builtins.h            |  2 +-
 src/builtins/arithmetic.c | 10 ++---
 src/builtins/arithmetic.h |  2 +-
 src/builtins/core.c       | 94 +++++++++++++++++++--------------------
 src/builtins/core.h       |  2 +-
 src/dict.c                |  6 ++-
 src/eval.c                | 20 +++++----
 src/eval.h                |  2 +-
 10 files changed, 80 insertions(+), 70 deletions(-)

diff --git a/ideas.org b/ideas.org
index c8b9514..9690f46 100644
--- a/ideas.org
+++ b/ideas.org
@@ -1,3 +1,9 @@
+
+so i'm redoing the basic eval to not pass an arg, but pass the rest of the list... yeah?
+then the builtins just harvest the rest one at a time to get all their args,
+and when executed can modify the rest? cool sounds good and worthwhile
+
+
 GARBAGE COLLECTION
 my grand design is that I will allocate and deallocate all the time, that is, if I 'def' something I keep it, but dereferencing something clones the thing, and then any call using it frees it again.
 is that too slow? yeah probably
diff --git a/src/builtins.c b/src/builtins.c
index f7a5761..90cf1c1 100644
--- a/src/builtins.c
+++ b/src/builtins.c
@@ -14,13 +14,13 @@
 #include <stdio.h>
 
 
-Sexpr* dispatch(Sexpr* b, Sexpr* env) {
+Sexpr* dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	uint64_t prefix = (b->value.b.opcode) >> 8;
 	switch(prefix) {
 	case CORE_PREFIX:
-		return x_core_dispatch(b, env);
+		return x_core_dispatch(b, rest, env);
 	case ARITH_PREFIX:
-		return x_arith_dispatch(b, env);
+		return x_arith_dispatch(b, rest, env);
 	default:
 		return from_nil();
 	}
diff --git a/src/builtins.h b/src/builtins.h
index 51b1aab..c20e829 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -5,7 +5,7 @@
 
 #include "builtins/core.h"
 
-Sexpr* dispatch(Sexpr* b, Sexpr* env);
+Sexpr* dispatch(Sexpr* b, Sexpr* rest, Sexpr* env);
 uint64_t u64_get_num_args(Sexpr* b);
 Sexpr* load_env(Sexpr* env);
 
diff --git a/src/builtins/arithmetic.c b/src/builtins/arithmetic.c
index c612272..8a04be5 100644
--- a/src/builtins/arithmetic.c
+++ b/src/builtins/arithmetic.c
@@ -10,22 +10,22 @@
 #include <stdlib.h>
 
 
-Sexpr* a_plus(Sexpr* b, Sexpr* env) {
+Sexpr* a_plus(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(ARITH_PLUS_ARGS != u64_get_num_args(b)) {
-		return b;
+		return cons(b, rest);
 	}
 	Sexpr* args = b->value.b.args;
 	uint64_t m = eval(car(args), env)->value.u;
 	uint64_t n = eval(car(cdr(args)), env)->value.u;
-	return from_uint(m + n);
+	return cons(from_uint(m + n), rest);
 }
 
-Sexpr* x_arith_dispatch(Sexpr* b, Sexpr* env) {
+Sexpr* x_arith_dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	uint64_t code = b->value.b.opcode & 0xff;
 
 	switch(code) {
 	case ARITH_PLUS:
-		return a_plus(b, env);
+		return a_plus(b, rest, env);
 	default:
 		return from_nil();
 	}
diff --git a/src/builtins/arithmetic.h b/src/builtins/arithmetic.h
index 6c3fa8f..bbfa4f0 100644
--- a/src/builtins/arithmetic.h
+++ b/src/builtins/arithmetic.h
@@ -9,7 +9,7 @@
 #define ARITH_PLUS 0x00
 #define ARITH_PLUS_ARGS 2
 
-Sexpr* x_arith_dispatch(Sexpr* s, Sexpr* env);
+Sexpr* x_arith_dispatch(Sexpr* s, Sexpr* rest, Sexpr* env);
 Sexpr* load_arith_env(Sexpr* env);
 
 #endif
diff --git a/src/builtins/core.c b/src/builtins/core.c
index 244ba49..99eb17c 100644
--- a/src/builtins/core.c
+++ b/src/builtins/core.c
@@ -12,126 +12,126 @@
 
 #include <stdio.h>
 
-Sexpr* c_quote(Sexpr* b, Sexpr* env) {
+Sexpr* c_quote(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_QUOTE_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	//return car(b->value.b.args);
-	return from_quote(car(b->value.b.args));
+	return cons(from_quote(car(b->value.b.args)), rest);
 }
 
 // redo the rest of these...
-Sexpr* c_cons(Sexpr* b, Sexpr* env) {
+Sexpr* c_cons(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_CONS_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
 	Sexpr* _cdr = eval(car(args), env);
 	Sexpr* _car = eval(car(cdr(args)), env);
-	return cons(_car, _cdr);
+	return cons(cons(_car, _cdr), rest);
 }
-Sexpr* c_car(Sexpr* b, Sexpr* env) {
+Sexpr* c_car(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_CAR_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
-	return car(eval(car(args), env));
+	// huh okay, can i ditch the eval now that i'm doing the 'rest' thing?
+	return cons(car(eval(car(args), env)), rest);
 }
-Sexpr* c_cdr(Sexpr* b, Sexpr* env) {
+Sexpr* c_cdr(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_CDR_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
-	return cdr(eval(car(args), env));
+	// see above
+	return cons(cdr(eval(car(args), env)), rest);
 }
-Sexpr* c_if(Sexpr* b, Sexpr* env) {
+Sexpr* c_if(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_IF_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
 	
 	Sexpr* falsy = car(args);
 	Sexpr* truthy = car(cdr(args));
 	Sexpr* cond = car(cdr(cdr(args)));
 	if(eval(cond, env)->type != NIL)
-		return truthy;
+		return cons(truthy, rest);
 	else
-		return falsy;
-	// uhhh am I sure about this one?
-	// the lack of evals is perhaps a little suspect...
+		return cons(falsy, rest);
 }
-Sexpr* c_eq(Sexpr* b, Sexpr* env) {
+Sexpr* c_eq(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_EQ_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
 	// yeah eval is kinda necessary for this one I'd say
 	Sexpr* lh = eval(car(args), env);
 	Sexpr* rh = eval(car(cdr(args)), env);
 	if(equal(lh, rh)->type == T)
-		return from_t();
-	return from_nil();
+		return cons(from_t(), rest);
+	return cons(from_nil(), rest);
 }
-Sexpr* c_not(Sexpr* b, Sexpr* env) {
-		if(CORE_NOT_ARGS != u64_get_num_args(b))
-		return b;
+Sexpr* c_not(Sexpr* b, Sexpr* rest, Sexpr* env) {
+	if(CORE_NOT_ARGS != u64_get_num_args(b))
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
 	// I guess I would need the eval to check if eventually is nil
 	if(eval(car(args), env)->type == NIL)
-		return from_t();
-	return from_nil();
+		return cons(from_t(), rest);
+	return cons(from_nil(), rest);
 }
-Sexpr* c_atom(Sexpr* b, Sexpr* env) {
+Sexpr* c_atom(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_ATOM_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
 	Sexpr* argeval = eval(car(args), env);
 	while(argeval->type == QUOTE) {
 		argeval = argeval->value.q;
 	}
 	if(argeval->type != CONS) {
-		return from_t();
+		return cons(from_t(), rest);
 	}
-	return from_nil();
+	return cons(from_nil(), rest);
 }
 
 
-Sexpr* c_def(Sexpr* b, Sexpr* env) {
+Sexpr* c_def(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_DEF_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
 	Sexpr* val = eval(car(args), env);
 	Sexpr* key = car(cdr(args));
 	append_to_dict(env, key, val);
-	return val;
+	return cons(val, rest);
 }
-Sexpr* c_exit(Sexpr* b, Sexpr* env) {
+Sexpr* c_exit(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	if(CORE_EXIT_ARGS != u64_get_num_args(b))
-		return b;
+		return cons(b, rest);
 	Sexpr* args = b->value.b.args;
 	uint64_t value = car(args)->value.u;
 	exit(value);
 	return NULL;
 }
 
-Sexpr* x_core_dispatch(Sexpr* b, Sexpr* env) {
+Sexpr* x_core_dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
 	uint64_t code = b->value.b.opcode & 0xff;
 
 	switch(code) {
 	case CORE_QUOTE:
-		return c_quote(b, env);
+		return c_quote(b, rest, env);
 	case CORE_CONS:
-		return c_cons(b, env);
+		return c_cons(b, rest, env);
 	case CORE_CAR:
-		return c_car(b, env);
+		return c_car(b, rest, env);
 	case CORE_CDR:
-		return c_cdr(b, env);
+		return c_cdr(b, rest, env);
 	case CORE_IF:
-		return c_if(b, env);
+		return c_if(b, rest, env);
 	case CORE_EQ:
-		return c_eq(b, env);
+		return c_eq(b, rest, env);
 	case CORE_NOT:
-		return c_not(b, env);
+		return c_not(b, rest, env);
 	case CORE_ATOM:
-		return c_atom(b, env);
+		return c_atom(b, rest, env);
 	case CORE_DEF:
-		return c_def(b, env);
+		return c_def(b, rest, env);
 	case CORE_EXIT:
-		return c_exit(b, env);
+		return c_exit(b, rest, env);
 	default:
 		return from_nil();
 	}
diff --git a/src/builtins/core.h b/src/builtins/core.h
index c85342e..72cb421 100644
--- a/src/builtins/core.h
+++ b/src/builtins/core.h
@@ -30,7 +30,7 @@
 #define CORE_EXIT 0xff
 #define CORE_EXIT_ARGS 1
 
-Sexpr* x_core_dispatch(Sexpr* s, Sexpr* env);
+Sexpr* x_core_dispatch(Sexpr* s, Sexpr* rest, Sexpr* env);
 Sexpr* load_core_env(Sexpr* env);
 
 #endif
diff --git a/src/dict.c b/src/dict.c
index 92c088d..c28498e 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -23,7 +23,8 @@ Sexpr* init_dict() {
 Sexpr* append_to_dict(Sexpr* dict, Sexpr* key, Sexpr* value) {
 	// assumes dict well-formed, returns new dict
 	// puts new things on the front of the dict, makes it so looking up gets the newest stuff first
-	Sexpr* new = cons(key, value);
+	Sexpr* new = cons(key, clone(value));
+	// not yet sure if the above 'clone' is needed, or where the call should take place
 	Sexpr* head = cons(new, car(dict));
 	dict->value.c->car = head;
 	//return cons(new, dict);
@@ -36,7 +37,8 @@ Sexpr* lookup(Sexpr* dict, Sexpr* key) {
 	Sexpr* node = car(dict);
 		while(node->type != NIL) {
 			if(equal(key, car(car(node)))->type == T) {
-				return cons(cdr(car(node)), from_nil());
+				Sexpr* value = clone(cdr(car(node)));
+				return cons(value, from_nil());
 			}
 			node = cdr(node);
 	}
diff --git a/src/eval.c b/src/eval.c
index 031fb25..cb99014 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -10,7 +10,7 @@
 Sexpr* apply_builtin(Sexpr* func, Sexpr* arg, Sexpr* env);
 
 Sexpr* eval(Sexpr* s, Sexpr* dict) {
-	//printf("s: %s\n", sprint_sexpr(s));
+	printf("s: %s\n", sprint_sexpr(s));
 	// non-null s
 	// generally assumes that a sexpr passed to this is well-formed (ie no inapt NULLS)
 	// question: does a completed builtin get evaluated here?
@@ -29,23 +29,25 @@ Sexpr* eval(Sexpr* s, Sexpr* dict) {
 	} // from now on: type is cons
 	Sexpr* curr = s;
 	while(curr->type == CONS) {
-		if(cdr(curr)->type == NIL)
+		if(cdr(curr)->type == NIL) // this is okay to keep, yeah
 			return eval(car(curr), dict);
 		if(cdr(curr)->type != CONS)
 			// need to redo, how do i eval "(f . x)" ?
 			// ^ easy, just return (f . x)
 			return curr;
 		// now i need to apply actually
-		Sexpr* arg = car(cdr(curr));
+		//Sexpr* arg = car(cdr(curr));
+		Sexpr* rest = cdr(curr);
 		Sexpr* func = eval(car(curr), dict);
-		Sexpr* newcar = apply_builtin(func, arg, dict);
-		Sexpr* newcdr = cdr(cdr(curr));
-		curr = cons(newcar, newcdr);
+		//Sexpr* newcar = apply_builtin(func, arg, dict);
+		//Sexpr* newcdr = cdr(cdr(curr));
+		curr = apply_builtin(func, rest, dict); // is this ok?
+		//curr = cons(newcar, newcdr);
 	}
 	return curr;
 }
 
-Sexpr* apply_builtin(Sexpr* func, Sexpr* arg, Sexpr* env) {
+Sexpr* apply_builtin(Sexpr* func, Sexpr* rest, Sexpr* env) {
 	if(func->type != BUILTIN) {
 		printf("uh oh\n");
 		return from_nil(); // uhh this /should/ actually be impossible...
@@ -53,8 +55,8 @@ Sexpr* apply_builtin(Sexpr* func, Sexpr* arg, Sexpr* env) {
 	Sexpr* ret = malloc(sizeof(Sexpr));
 	ret->type = BUILTIN;
 	ret->value.b.opcode = func->value.b.opcode;
-	ret->value.b.args = cons(arg, func->value.b.args);
+	ret->value.b.args = cons(car(rest), func->value.b.args);
 	
-	return dispatch(ret, env);
+	return dispatch(ret, cdr(rest), env);
 	// applies if correct no of args, just returns self otherwise
 }
diff --git a/src/eval.h b/src/eval.h
index db625cc..358df08 100644
--- a/src/eval.h
+++ b/src/eval.h
@@ -10,7 +10,7 @@
 // key type is string, value type is sexpr, hash range is uint64_t
 
 Sexpr* eval(Sexpr* s, Sexpr* env);
-Sexpr* apply_builtin(Sexpr* func, Sexpr* arg, Sexpr* env);
+Sexpr* apply_builtin(Sexpr* func, Sexpr* rest, Sexpr* env);
 
 
 
-- 
2.39.5