From 1d5621923c5ba69723098c1d2a360351df330655 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Tue, 15 Mar 2022 15:26:01 -0400 Subject: [PATCH] Further flesh-out structs. Temporarily disable http due to buggy Ubuntu libmicrohttpd. Add a way to access their fields with `'s`. - Uses some fairly hacky parseAtom additions. Needs to be refined. Add structCapacity to Environment. Add global Environment pointer. Use structDef indexes instead of direct pointers. - Easier to increase capacity this way strcpy struct field names --- src/env.c | 4 ++ src/env.h | 2 + src/examples/webby.pl | 17 ++++++ src/object.c | 13 ++--- src/object.h | 7 +-- src/pebblisp.c | 118 ++++++++++++++++++++++++++++++------------ src/pebblisp.h | 4 +- 7 files changed, 123 insertions(+), 42 deletions(-) create mode 100644 src/examples/webby.pl diff --git a/src/env.c b/src/env.c index a1b0e65..b323792 100644 --- a/src/env.c +++ b/src/env.c @@ -52,6 +52,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, .strings = NULL, .objects = NULL, .structCount = 0, + .structCapacity = 0, .size = paramCount, .refs = 1, }; @@ -226,6 +227,8 @@ struct Environment defaultEnv() .objects = objects, .size = size, .structCount = 0, + .structCapacity = 8, + .structDefs = malloc(sizeof(struct StructDef) * 8), .refs = 1, }; @@ -256,6 +259,7 @@ struct Environment defaultEnv() {"iserr", &isErr}, {"char", &charVal}, {"eval", &parseEvalO}, + {"poss", &possessive}, #ifdef STANDALONE {"prn", &print}, {"pch", &pChar}, diff --git a/src/env.h b/src/env.h index c3acbfc..a431d63 100644 --- a/src/env.h +++ b/src/env.h @@ -11,10 +11,12 @@ struct Environment { int size; int structCount; + int structCapacity; struct StructDef* structDefs; int refs; }; +struct Environment* global; Object fetchFromEnvironment(const char* name, struct Environment* env); diff --git a/src/examples/webby.pl b/src/examples/webby.pl new file mode 100644 index 0000000..c063773 --- /dev/null +++ b/src/examples/webby.pl @@ -0,0 +1,17 @@ +(struct post + (title body)) + +(def x (post "Hey" "This is a post")) + +(def html (fn (text) (cat "" text ""))) +(def body (fn (text) (cat "" text ""))) +(def h1 (fn (text) (cat "

" text "

"))) +(def p (fn (text) (cat "

" text "

"))) + +(def htmlize (fn (po) + (html + (body (cat + (h1 po's title) + (p po's body)))))) + +(prnl (htmlize x)) diff --git a/src/object.c b/src/object.c index 917a840..e363920 100644 --- a/src/object.c +++ b/src/object.c @@ -1,4 +1,5 @@ #include "object.h" +#include "env.h" #include #include @@ -266,9 +267,9 @@ void stringStruct(char* dest, const Object* obj) dest[0] = '{'; dest[1] = '\0'; - for (int i = 0; i < so->definition->fieldCount; i++) { + for (int i = 0; i < global->structDefs[so->definition].fieldCount; i++) { strcat(dest, " "); - strcat(dest, so->definition->names[i]); + strcat(dest, global->structDefs[so->definition].names[i]); strcat(dest, ": "); int isString = so->fields[i].type == TYPE_STRING; if (isString) { @@ -505,7 +506,7 @@ void cleanObject(Object* target) free(target->lambda); break; case TYPE_STRUCT: - for (int i = 0; i < target->structObject->definition->fieldCount; i++) { + for (int i = 0; i < global->structDefs[target->structObject->definition].fieldCount; i++) { cleanObject(&target->structObject->fields[i]); } free(target->structObject->fields); @@ -651,12 +652,12 @@ inline Object listObject() } // Returns an empty struct Object -inline Object structObject(struct StructDef *definition) +inline Object structObject(int definition) { Object structo = newObject(TYPE_STRUCT); structo.structObject = malloc(sizeof(struct StructObject)); structo.structObject->definition = definition; - structo.structObject->fields = malloc(sizeof(Object) * definition->fieldCount); + structo.structObject->fields = malloc(sizeof(Object) * global->structDefs[definition].fieldCount); return structo; } @@ -760,7 +761,7 @@ Object cloneStruct(const Object src) { Object structo = structObject(src.structObject->definition); struct StructObject* so = structo.structObject; - for (int i = 0; i < so->definition->fieldCount; i++) { + for (int i = 0; i < global->structDefs[so->definition].fieldCount; i++) { so->fields[i] = cloneObject(src.structObject->fields[i]); } return structo; diff --git a/src/object.h b/src/object.h index 3ee96aa..ef04eba 100644 --- a/src/object.h +++ b/src/object.h @@ -117,11 +117,12 @@ struct Object { struct StructDef { int fieldCount; char* name; - const char** names; + char** names; }; struct StructObject { - struct StructDef *definition; + int definition; + //struct StructDef *definition; struct Object* fields; // Order should match that in the definition. }; @@ -218,7 +219,7 @@ Object boolObject(int b); Object numberObject(int num); -Object structObject(struct StructDef *definition); +Object structObject(int definition); Object otherObject(); diff --git a/src/pebblisp.c b/src/pebblisp.c index 4902033..a78c183 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -77,17 +77,31 @@ Object evalStructArgs(const Object* symbol, const Object* fields, struct Environ int i = 0; FOR_POINTER_IN_LIST(fields) { - def.names[i] = POINTER->string; + def.names[i] = malloc(sizeof(char) * (strlen(POINTER->string) + 1)); + strcpy(def.names[i], POINTER->string); i++; } while (env->outer) { env = env->outer; } - env->structDefs = malloc(sizeof(struct StructDef) * 1); - env->structCount = 1; - env->structDefs[0] = def; - printStructDef(&env->structDefs[0]); + + env->structDefs[env->structCount] = def; + //printStructDef(&env->structDefs[env->structCount]); + env->structCount += 1; + if (env->structCount == env->structCapacity) { + struct StructDef* prev = env->structDefs; + int prevCapacity = env->structCapacity; + env->structCapacity *= 2; + env->structDefs = malloc(sizeof(struct StructDef) * env->structCapacity); + printf("Can malloc\n"); + //memcpy(env->structDefs, prev, sizeof(struct StructDef) * prevCapacity); + //printf("Can memcpy\n"); + for (int i = 0; i < prevCapacity; i++) { + env->structDefs[i] = prev[i]; + } + free(prev); + } return boolObject(1); } @@ -307,7 +321,8 @@ Object evalList(const Object* obj, struct Environment* env) cleanObject(&builtIn); } - struct StructDef *def = NULL; + //struct StructDef *def = NULL; + int def = -1; if (first_form->type == TYPE_SYMBOL) { struct Environment* outerEnv = env; while (outerEnv->outer) { @@ -319,13 +334,13 @@ Object evalList(const Object* obj, struct Environment* env) for (int i = 0; i < outerEnv->structCount; i++) { //printf("struct[%d] - `%s`\n", i, outerEnv->structDefs[i].name); if (strcmp(first_form->string, outerEnv->structDefs[i].name) == 0) { - def = &outerEnv->structDefs[i]; - printf("Found struct definition for %s!\n", first_form->string); + def = i; + //printf("Found struct definition for %s!\n", first_form->string); break; } } } - if (def) { + if (def >= 0) { Object structo = structObject(def); int i = 0; FOR_POINTER_IN_LIST(obj) { @@ -649,25 +664,25 @@ Object print(Object p, Object ignore, struct Environment* env) Object addRouteO(Object path, Object textFunc, struct Environment* env) { - const char* p = malloc(sizeof(char) * strlen(path.string) + 1); - strcpy(p, path.string); - //const char* t = malloc(sizeof(char) * strlen(textFunc.string) + 1); - //strcpy(t, textFunc.string); + // const char* p = malloc(sizeof(char) * strlen(path.string) + 1); + // strcpy(p, path.string); + // //const char* t = malloc(sizeof(char) * strlen(textFunc.string) + 1); + // //strcpy(t, textFunc.string); - struct Route r; - r.path = p; - r.routeAction = cloneObject(textFunc); - r.env = env; - env->refs += 1; - //r.text = t; - addRoute(r); + // struct Route r; + // r.path = p; + // r.routeAction = cloneObject(textFunc); + // r.env = env; + // env->refs += 1; + // //r.text = t; + // addRoute(r); return numberObject(1); } Object startServer(Object path, Object textFunc, struct Environment* env) { - return numberObject(start(8888)); + return numberObject(1/*start(8888)*/); } Object pChar(Object c, Object i1, struct Environment* i2) @@ -743,6 +758,31 @@ void debugSlice(struct Slice* s) #endif } +Object possessive(Object structo, Object field, struct Environment* env) +{ + if (structo.type != TYPE_STRUCT) { + printf("`'s` must be used on a struct!\n"); + return errorObject(NULL_PARSE); + } + if (!isStringy(field)) { + printf("`'s` field name must be stringy! Received a "); + printType(&field); + printObj(&field); + printf("\n"); + return errorObject(NULL_PARSE); + } + + struct StructDef structDef = global->structDefs[structo.structObject->definition]; + for (int i = 0; i < structDef.fieldCount; i++) { + if (strcmp(field.string, structDef.names[i]) == 0) { + return cloneObject(structo.structObject->fields[i]); + } + } + + printf("Could not find field name `%s`\n", field.string); + return errorObject(NULL_PARSE); +} + Result parse(struct Slice* slices) { struct Slice* token = slices; @@ -756,7 +796,9 @@ Result parse(struct Slice* slices) // todo check for null rest return readSeq(rest); } else { // todo error on missing close paren - return (Result) {parseAtom(token), rest}; + Result r = parseAtom(token); + r.slices = &r.slices[1]; + return r; } } else { return (Result) {errorObject(NULL_PARSE), NULL}; @@ -827,29 +869,40 @@ Object parseBin(struct Slice* s) return numberObject(num); } -Object parseAtom(struct Slice* s) +Result parseAtom(struct Slice* s) { const char c = s->text[0]; if (isDigit(c)) { if (c != '0' || s->length == 1) { - return parseDecimal(s); + return (Result) {parseDecimal(s), s}; #ifndef LOW_MEM } else if (c == '0' && s->text[1] == 'x') { - return parseHex(s); + return (Result) {parseHex(s), s}; } else if (c == '0' && s->text[1] == 'b') { - return parseBin(s); + return (Result) { parseBin(s), s }; #endif } else { - return errorObject(UNSUPPORTED_NUMBER_TYPE); + return (Result) { errorObject(UNSUPPORTED_NUMBER_TYPE), s}; } } else if (s->length == 1 && (c == 'T' || c == 't')) { - return boolObject(1); + return (Result) { boolObject(1), s}; } else if (s->length == 1 && (c == 'F' || c == 'f')) { - return boolObject(0); - } else if (c == '"' || c == '\'') { - return objFromSlice(s->text, s->length); + return (Result) { boolObject(0), s}; + } else if (c == '"'/* || c == '\''*/) { + return (Result) { objFromSlice(s->text, s->length), s}; } else { - return symFromSlice(s->text, s->length); + if (s->text[s->length] == '\'' && s->text[s->length + 1] == 's') { + Object possessiveFunc = newObject(TYPE_FUNC); + possessiveFunc.func = &possessive; + Object list = startList(possessiveFunc); + Object possesser = symFromSlice(s->text, s->length); + nf_addToList(&list, possesser); + struct Slice* next = s + 3; + Object possessed = objFromSlice(&next->text[-1], next->length + 1); + nf_addToList(&list, possessed); + return (Result) { list, next }; + } + return (Result) { symFromSlice(s->text, s->length), s}; } } @@ -1005,6 +1058,7 @@ void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env) int main(int argc, const char* argv[]) { struct Environment env = defaultEnv(); + global = &env; readFile(SCRIPTDIR "/lib.pbl", &env); if (argc >= 2) { FILE* file = fopen(argv[1], "r"); diff --git a/src/pebblisp.h b/src/pebblisp.h index f742d70..52c4e26 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -20,7 +20,7 @@ Result parse(struct Slice* slices); Result readSeq(struct Slice* slices); -Object parseAtom(struct Slice* slice); +Result parseAtom(struct Slice* slice); Object parseEval(const char* input, struct Environment* env); @@ -94,6 +94,8 @@ Object printEnvO(Object i1, Object i2, struct Environment* env); Object parseEvalO(Object text, Object ignore, struct Environment* env); +Object possessive(Object structo, Object field, struct Environment* env); + #ifdef STANDALONE Object takeInput(Object i1, Object i2, struct Environment* i3);