From 3285a8c1b858fdad71758ba8f631f017437e004d Mon Sep 17 00:00:00 2001 From: Elijah Cohen Date: Tue, 23 Jul 2024 19:26:30 -0500 Subject: [PATCH] some infra for builtins, mostly commit before makefile changes --- ideas.org | 16 +++++++++++++++ src/builtins.c | 20 ++++++++++++++++++ src/builtins.h | 14 +++++++++++++ src/builtins/core.c | 18 +++++++++++++++++ src/builtins/core.h | 11 ++++++++++ src/dict.c | 3 ++- src/eval.c | 49 +++++++++++++++++++++++++++++++++++++++------ src/sexpr.c | 8 +++++++- src/test.c | 2 +- src/types.h | 8 ++++++++ 10 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 src/builtins.c create mode 100644 src/builtins.h create mode 100644 src/builtins/core.c create mode 100644 src/builtins/core.h diff --git a/ideas.org b/ideas.org index 3b6a1e7..f2dc099 100644 --- a/ideas.org +++ b/ideas.org @@ -1,4 +1,20 @@ + +OPCODES: each 'page' has 256 diff opts, splits prior to that for maintainability or whatever + +OKAY MAIN PROBLEM NOW: +for the builtins, I need to literally clone them all the time whenever I need a new one, or else the args pointer stays the same and it effects other calls of the function +solution! I just initialize to null, and make a clone when I need to I guess + + +NOTE ON HOW I ACTUALLY INTEND TO DO THIS +THIS REFERRING TO HANDLING EVALUATIONS OF BUILTINS +I think maybe a struct storing the opcode and a pointer to a sexpr representing a list of args might be the way to do it, plus a uint for num of args? + +also I want each individual opcode to decide whether or not and how to evaluate its own arguments + + + So this is a poorly-named directory, since what I'm making will end up being a lisp-1... thinking about taking ideas from concatenative languages, tacit programming, and the such. diff --git a/src/builtins.c b/src/builtins.c new file mode 100644 index 0000000..74ddec4 --- /dev/null +++ b/src/builtins.c @@ -0,0 +1,20 @@ + + +#include "types.h" +#include "sexpr.h" + + +// this is where you include whatever extra sets of instructions + +#include "builtins/core.h" + + +Sexpr* dispatch(Sexpr* b) { + uint64_t prefix = (b->value.b.opcode) >> 8; + switch(prefix) { + case CORE_PREFIX: + return x_core_dispatch(b); + default: + return from_nil(); + } +} diff --git a/src/builtins.h b/src/builtins.h new file mode 100644 index 0000000..cc110c3 --- /dev/null +++ b/src/builtins.h @@ -0,0 +1,14 @@ +#ifndef _BUILTINS_H +#define _BUILTINS_H + +#include "types.h" + +#include "builtins/core.h" + +#define _HIIIII + +Sexpr* dispatch(Sexpr* b); + + + +#endif diff --git a/src/builtins/core.c b/src/builtins/core.c new file mode 100644 index 0000000..8e08682 --- /dev/null +++ b/src/builtins/core.c @@ -0,0 +1,18 @@ + + +#include "../types.h" +#include "../sexpr.h" +#include "../eval.h" + + + +Sexpr* x_core_dispatch(Sexpr* s) { + uint64_t code = s->value.b.opcode & 0xff; + switch(code) { + case 0: // quote + + default: + return from_nil(); + } + return from_nil(); +} diff --git a/src/builtins/core.h b/src/builtins/core.h new file mode 100644 index 0000000..7f941e0 --- /dev/null +++ b/src/builtins/core.h @@ -0,0 +1,11 @@ + + +#include "../types.h" + +// need to define + +#define CORE_PREFIX 0x00 + + +Sexpr* x_core_dispatch(Sexpr* s); + diff --git a/src/dict.c b/src/dict.c index fc2053e..dd5aa4f 100644 --- a/src/dict.c +++ b/src/dict.c @@ -23,10 +23,11 @@ Sexpr* append_to_dict(Sexpr* dict, Sexpr* key, Sexpr* value) { Sexpr* lookup(Sexpr* dict, Sexpr* key) { // assumes dict well-formed + // returns nil if not found, returns (result) if it is Sexpr* node = dict; while(node->type != NIL) { if(equal(key, car(car(node)))->type == T) { - return cdr(car(node)); + return cons(cdr(car(node)), from_nil()); } node = cdr(node); } diff --git a/src/eval.c b/src/eval.c index 9d68efe..a28fd07 100644 --- a/src/eval.c +++ b/src/eval.c @@ -4,23 +4,60 @@ #include "types.h" #include "sexpr.h" +#include "dict.h" +#include "builtins.h" +Sexpr* apply_builtin(Sexpr* func, Sexpr* arg); -Sexpr* eval(Sexpr* s) { +Sexpr* eval(Sexpr* s, Sexpr* dict) { // 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? if(s == NULL) return NULL; // not needed if assumptions accurate, but yknow if(s->type == SYM) { // look up the value in the lookup table - return s; + return car(lookup(dict, s)); } if(s->type != CONS) { return s; } // from now on: type is cons - if(cdr(s) == NULL) { - return car(s); - } // from now on: a function of some sort is being called + Sexpr* curr = s; + while(curr->type == CONS) { + if(cdr(curr)->type == NIL) + //return eval(car(curr), dict); + return car(curr); + if(cdr(curr)->type != CONS) + // need to redo, how do i eval "(f . x)" ? + return car(curr); + // now i need to apply actually + Sexpr* arg = car(cdr(curr)); + Sexpr* func = car(curr); + Sexpr* newcar = apply_builtin(func, arg); + Sexpr* newcdr = cdr(cdr(curr)); + curr = cons(newcar, newcdr); + } + return curr; +} - return NULL; +Sexpr* apply_builtin(Sexpr* func, Sexpr* arg) { + if(func->type != BUILTIN) + return from_nil(); // uhh this /should/ actually be impossible... + uint8_t num_args = 0; + Sexpr* curr = func->value.b.args; + while(curr->type != NIL) { + curr = cdr(curr); + num_args++; + } + Sexpr* ret = malloc(sizeof(Sexpr)); + if(num_args < func->value.b.num_args_needed) { + ret->type = BUILTIN; + ret->value.b.opcode = func->value.b.opcode; + ret->value.b.num_args_needed = func->value.b.num_args_needed; + ret->value.b.args = cons(arg, func->value.b.args); + } + if(num_args+1 < func->value.b.num_args_needed) + return ret; + // what's left now: all the args needed are there, + // just gotta dispatch to whatever handles the opcode evals + return dispatch(ret); } diff --git a/src/sexpr.c b/src/sexpr.c index 126b124..fbe4994 100644 --- a/src/sexpr.c +++ b/src/sexpr.c @@ -63,7 +63,6 @@ Sexpr* equal(Sexpr* a, Sexpr* b) { return from_t(); if(t == T) return from_t(); - if(t == SYM) { return strcmp(a->value.s, b->value.s) == 0 ? from_t() : from_nil(); } @@ -122,6 +121,13 @@ char* sprint_sexpr(Sexpr* s) { snprintf(out, nbytes, "%" PRIu64 "", s->value.u); return out; } + else if(s->type == BUILTIN) { + nbytes = snprintf(NULL, 0, "%" PRIu64 "", s->value.u) + 2; + out = malloc(nbytes*sizeof(char)); + out[0] = '_'; + snprintf(out, nbytes+1, "%" PRIu64 "", s->value.u); + return out; + } else if(s->type == CONS) { Sexpr* curr_cell = s; size_t currsize = 2; diff --git a/src/test.c b/src/test.c index 550e6fb..8cd28c8 100644 --- a/src/test.c +++ b/src/test.c @@ -6,7 +6,7 @@ #include "sexpr.h" #include "parser.h" #include "dict.h" - +#include "eval.h" diff --git a/src/types.h b/src/types.h index b5a881a..caf3484 100644 --- a/src/types.h +++ b/src/types.h @@ -11,6 +11,7 @@ typedef char* Symbol_t; typedef void* Nil_t; typedef void* Truth_t; +//typedef uint64_t Builtin_t; typedef enum Sexpr_Type { UINT, SYM, BUILTIN, NIL, T, CONS, FEXP, FUN @@ -21,6 +22,12 @@ typedef struct Cons { struct Sexpr* cdr; } Cons_t; +typedef struct Builtin { + struct Sexpr* args; + uint64_t num_args_needed; + uint64_t opcode; +} Builtin_t; + typedef struct Closure { uint64_t opcode; uint64_t num_args; @@ -36,6 +43,7 @@ typedef struct Sexpr { Fexpr_t x; Fun_t f; uint64_t u; + Builtin_t b; Symbol_t s; Cons_t* c; Nil_t n; -- 2.39.2