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:
parent
11f39bf136
commit
1d5621923c
|
@ -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},
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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))
|
13
src/object.c
13
src/object.c
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
118
src/pebblisp.c
118
src/pebblisp.c
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue