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
This commit is contained in:
Sage Vaillancourt 2022-03-15 15:26:01 -04:00 committed by Sage Vaillancourt
parent 11f39bf136
commit 1d5621923c
7 changed files with 123 additions and 42 deletions

View File

@ -52,6 +52,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms,
.strings = NULL, .strings = NULL,
.objects = NULL, .objects = NULL,
.structCount = 0, .structCount = 0,
.structCapacity = 0,
.size = paramCount, .size = paramCount,
.refs = 1, .refs = 1,
}; };
@ -226,6 +227,8 @@ struct Environment defaultEnv()
.objects = objects, .objects = objects,
.size = size, .size = size,
.structCount = 0, .structCount = 0,
.structCapacity = 8,
.structDefs = malloc(sizeof(struct StructDef) * 8),
.refs = 1, .refs = 1,
}; };
@ -256,6 +259,7 @@ struct Environment defaultEnv()
{"iserr", &isErr}, {"iserr", &isErr},
{"char", &charVal}, {"char", &charVal},
{"eval", &parseEvalO}, {"eval", &parseEvalO},
{"poss", &possessive},
#ifdef STANDALONE #ifdef STANDALONE
{"prn", &print}, {"prn", &print},
{"pch", &pChar}, {"pch", &pChar},

View File

@ -11,10 +11,12 @@ struct Environment {
int size; int size;
int structCount; int structCount;
int structCapacity;
struct StructDef* structDefs; struct StructDef* structDefs;
int refs; int refs;
}; };
struct Environment* global;
Object fetchFromEnvironment(const char* name, struct Environment* env); Object fetchFromEnvironment(const char* name, struct Environment* env);

17
src/examples/webby.pl Normal file
View File

@ -0,0 +1,17 @@
(struct post
(title body))
(def x (post "Hey" "This is a post"))
(def html (fn (text) (cat "<html>" text "</html>")))
(def body (fn (text) (cat "<body>" text "</body>")))
(def h1 (fn (text) (cat "<h1>" text "</h1>")))
(def p (fn (text) (cat "<p>" text "</p>")))
(def htmlize (fn (po)
(html
(body (cat
(h1 po's title)
(p po's body))))))
(prnl (htmlize x))

View File

@ -1,4 +1,5 @@
#include "object.h" #include "object.h"
#include "env.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -266,9 +267,9 @@ void stringStruct(char* dest, const Object* obj)
dest[0] = '{'; dest[0] = '{';
dest[1] = '\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, " ");
strcat(dest, so->definition->names[i]); strcat(dest, global->structDefs[so->definition].names[i]);
strcat(dest, ": "); strcat(dest, ": ");
int isString = so->fields[i].type == TYPE_STRING; int isString = so->fields[i].type == TYPE_STRING;
if (isString) { if (isString) {
@ -505,7 +506,7 @@ void cleanObject(Object* target)
free(target->lambda); free(target->lambda);
break; break;
case TYPE_STRUCT: 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]); cleanObject(&target->structObject->fields[i]);
} }
free(target->structObject->fields); free(target->structObject->fields);
@ -651,12 +652,12 @@ inline Object listObject()
} }
// Returns an empty struct Object // Returns an empty struct Object
inline Object structObject(struct StructDef *definition) inline Object structObject(int definition)
{ {
Object structo = newObject(TYPE_STRUCT); Object structo = newObject(TYPE_STRUCT);
structo.structObject = malloc(sizeof(struct StructObject)); structo.structObject = malloc(sizeof(struct StructObject));
structo.structObject->definition = definition; structo.structObject->definition = definition;
structo.structObject->fields = malloc(sizeof(Object) * definition->fieldCount); structo.structObject->fields = malloc(sizeof(Object) * global->structDefs[definition].fieldCount);
return structo; return structo;
} }
@ -760,7 +761,7 @@ Object cloneStruct(const Object src)
{ {
Object structo = structObject(src.structObject->definition); Object structo = structObject(src.structObject->definition);
struct StructObject* so = structo.structObject; 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]); so->fields[i] = cloneObject(src.structObject->fields[i]);
} }
return structo; return structo;

View File

@ -117,11 +117,12 @@ struct Object {
struct StructDef { struct StructDef {
int fieldCount; int fieldCount;
char* name; char* name;
const char** names; char** names;
}; };
struct StructObject { struct StructObject {
struct StructDef *definition; int definition;
//struct StructDef *definition;
struct Object* fields; // Order should match that in the definition. struct Object* fields; // Order should match that in the definition.
}; };
@ -218,7 +219,7 @@ Object boolObject(int b);
Object numberObject(int num); Object numberObject(int num);
Object structObject(struct StructDef *definition); Object structObject(int definition);
Object otherObject(); Object otherObject();

View File

@ -77,17 +77,31 @@ Object evalStructArgs(const Object* symbol, const Object* fields, struct Environ
int i = 0; int i = 0;
FOR_POINTER_IN_LIST(fields) { 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++; i++;
} }
while (env->outer) { while (env->outer) {
env = env->outer; env = env->outer;
} }
env->structDefs = malloc(sizeof(struct StructDef) * 1);
env->structCount = 1; env->structDefs[env->structCount] = def;
env->structDefs[0] = def; //printStructDef(&env->structDefs[env->structCount]);
printStructDef(&env->structDefs[0]); 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); return boolObject(1);
} }
@ -307,7 +321,8 @@ Object evalList(const Object* obj, struct Environment* env)
cleanObject(&builtIn); cleanObject(&builtIn);
} }
struct StructDef *def = NULL; //struct StructDef *def = NULL;
int def = -1;
if (first_form->type == TYPE_SYMBOL) { if (first_form->type == TYPE_SYMBOL) {
struct Environment* outerEnv = env; struct Environment* outerEnv = env;
while (outerEnv->outer) { while (outerEnv->outer) {
@ -319,13 +334,13 @@ Object evalList(const Object* obj, struct Environment* env)
for (int i = 0; i < outerEnv->structCount; i++) { for (int i = 0; i < outerEnv->structCount; i++) {
//printf("struct[%d] - `%s`\n", i, outerEnv->structDefs[i].name); //printf("struct[%d] - `%s`\n", i, outerEnv->structDefs[i].name);
if (strcmp(first_form->string, outerEnv->structDefs[i].name) == 0) { if (strcmp(first_form->string, outerEnv->structDefs[i].name) == 0) {
def = &outerEnv->structDefs[i]; def = i;
printf("Found struct definition for %s!\n", first_form->string); //printf("Found struct definition for %s!\n", first_form->string);
break; break;
} }
} }
} }
if (def) { if (def >= 0) {
Object structo = structObject(def); Object structo = structObject(def);
int i = 0; int i = 0;
FOR_POINTER_IN_LIST(obj) { 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) Object addRouteO(Object path, Object textFunc, struct Environment* env)
{ {
const char* p = malloc(sizeof(char) * strlen(path.string) + 1); // const char* p = malloc(sizeof(char) * strlen(path.string) + 1);
strcpy(p, path.string); // strcpy(p, path.string);
//const char* t = malloc(sizeof(char) * strlen(textFunc.string) + 1); // //const char* t = malloc(sizeof(char) * strlen(textFunc.string) + 1);
//strcpy(t, textFunc.string); // //strcpy(t, textFunc.string);
struct Route r; // struct Route r;
r.path = p; // r.path = p;
r.routeAction = cloneObject(textFunc); // r.routeAction = cloneObject(textFunc);
r.env = env; // r.env = env;
env->refs += 1; // env->refs += 1;
//r.text = t; // //r.text = t;
addRoute(r); // addRoute(r);
return numberObject(1); return numberObject(1);
} }
Object startServer(Object path, Object textFunc, struct Environment* env) 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) Object pChar(Object c, Object i1, struct Environment* i2)
@ -743,6 +758,31 @@ void debugSlice(struct Slice* s)
#endif #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) Result parse(struct Slice* slices)
{ {
struct Slice* token = slices; struct Slice* token = slices;
@ -756,7 +796,9 @@ Result parse(struct Slice* slices)
// todo check for null rest // todo check for null rest
return readSeq(rest); return readSeq(rest);
} else { // todo error on missing close paren } else { // todo error on missing close paren
return (Result) {parseAtom(token), rest}; Result r = parseAtom(token);
r.slices = &r.slices[1];
return r;
} }
} else { } else {
return (Result) {errorObject(NULL_PARSE), NULL}; return (Result) {errorObject(NULL_PARSE), NULL};
@ -827,29 +869,40 @@ Object parseBin(struct Slice* s)
return numberObject(num); return numberObject(num);
} }
Object parseAtom(struct Slice* s) Result parseAtom(struct Slice* s)
{ {
const char c = s->text[0]; const char c = s->text[0];
if (isDigit(c)) { if (isDigit(c)) {
if (c != '0' || s->length == 1) { if (c != '0' || s->length == 1) {
return parseDecimal(s); return (Result) {parseDecimal(s), s};
#ifndef LOW_MEM #ifndef LOW_MEM
} else if (c == '0' && s->text[1] == 'x') { } else if (c == '0' && s->text[1] == 'x') {
return parseHex(s); return (Result) {parseHex(s), s};
} else if (c == '0' && s->text[1] == 'b') { } else if (c == '0' && s->text[1] == 'b') {
return parseBin(s); return (Result) { parseBin(s), s };
#endif #endif
} else { } else {
return errorObject(UNSUPPORTED_NUMBER_TYPE); return (Result) { errorObject(UNSUPPORTED_NUMBER_TYPE), s};
} }
} else if (s->length == 1 && (c == 'T' || c == 't')) { } 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')) { } else if (s->length == 1 && (c == 'F' || c == 'f')) {
return boolObject(0); return (Result) { boolObject(0), s};
} else if (c == '"' || c == '\'') { } else if (c == '"'/* || c == '\''*/) {
return objFromSlice(s->text, s->length); return (Result) { objFromSlice(s->text, s->length), s};
} else { } 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[]) int main(int argc, const char* argv[])
{ {
struct Environment env = defaultEnv(); struct Environment env = defaultEnv();
global = &env;
readFile(SCRIPTDIR "/lib.pbl", &env); readFile(SCRIPTDIR "/lib.pbl", &env);
if (argc >= 2) { if (argc >= 2) {
FILE* file = fopen(argv[1], "r"); FILE* file = fopen(argv[1], "r");

View File

@ -20,7 +20,7 @@ Result parse(struct Slice* slices);
Result readSeq(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); 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 parseEvalO(Object text, Object ignore, struct Environment* env);
Object possessive(Object structo, Object field, struct Environment* env);
#ifdef STANDALONE #ifdef STANDALONE
Object takeInput(Object i1, Object i2, struct Environment* i3); Object takeInput(Object i1, Object i2, struct Environment* i3);