Use dynamically-sized strings for stringObj.

Fix webby.pl's `reduce` usage and web.c's struct creation.
This commit is contained in:
Sage Vaillancourt 2022-03-29 13:55:51 -04:00 committed by Sage Vaillancourt
parent af7a2e6265
commit a444bc11bb
7 changed files with 104 additions and 94 deletions

View File

@ -42,7 +42,6 @@ Object fetchFromEnvironment(const char* name, struct Environment* env)
} }
printd("Try %d (%s)\n", i, env->strings[i]); printd("Try %d (%s)\n", i, env->strings[i]);
debugObj(&env->objects[i]);
if (strcmp(name, env->strings[i]) == 0) { printd("Returning!\n"); if (strcmp(name, env->strings[i]) == 0) { printd("Returning!\n");
return cloneObject(env->objects[i]); return cloneObject(env->objects[i]);
} }
@ -85,7 +84,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, i
for (int i = 0; i < paramCount; i++) { for (int i = 0; i < paramCount; i++) {
const char* newObjName = itemAt(params, i)->string; const char* newObjName = itemAt(params, i)->string;
// Eval the `march` list // Eval the `march` list
Object newEnvObj = march ? eval(march, outer) : errorObject(NOT_ENOUGH_ARGUMENTS); Object newEnvObj = march ? eval(march, outer) : errorWithContext(NOT_ENOUGH_ARGUMENTS, newObjName);
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms? addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms?
cleanObject(&newEnvObj); cleanObject(&newEnvObj);
march = march ? march->forward : NULL; march = march ? march->forward : NULL;
@ -324,7 +323,6 @@ int runTests(int detailed)
for (int hi = 0; hi < currentHelp; hi++) { for (int hi = 0; hi < currentHelp; hi++) {
struct helpText h = helpTexts[hi]; struct helpText h = helpTexts[hi];
if (h.tests) { if (h.tests) {
char result[1024];
if (detailed && h.testCount > 0) { if (detailed && h.testCount > 0) {
printf(" `%s` ", h.symbol); printf(" `%s` ", h.symbol);
} }
@ -333,7 +331,8 @@ int runTests(int detailed)
const char* expected = h.tests[ti + 1]; const char* expected = h.tests[ti + 1];
struct Environment env = defaultEnv(); struct Environment env = defaultEnv();
Object o = parseEval(test, &env); Object o = parseEval(test, &env);
stringObj(result, &o); size_t length;
char* result = stringObj(&o, &length);
cleanObject(&o); cleanObject(&o);
if (strcmp(result, expected) != 0) { if (strcmp(result, expected) != 0) {
failureCount++; failureCount++;
@ -346,6 +345,7 @@ int runTests(int detailed)
} }
passCount++; passCount++;
} }
free(result);
deleteEnv(&env); deleteEnv(&env);
} }
if (detailed && h.testCount > 0) { if (detailed && h.testCount > 0) {

View File

@ -6,7 +6,7 @@
(def element (fn (type) (def element (fn (type)
(fn (text) (fn (text)
(cat "<" type ">" (cat "<" type ">"
(if (islist text) (reduce (text "") cat) (reduce ((text) "") cat)) (if (islist text) (reduce text cat "") (reduce (text) cat ""))
"</" type ">")))) "</" type ">"))))
(def html (element "html")) (def html (element "html"))
@ -49,10 +49,8 @@ stuff, when you think about it."
(htmlize p2))) (htmlize p2)))
)))) ))))
(def revealer (fn (x) (cat "" x)))
(get "/" homepage) (get "/" homepage)
(get "/x" revealer) (get "/x" (fn (req) (cat "" req)))
(def styles (rf "styles.css")) (def styles (rf "styles.css"))
(get "/styles.css" (fn () (styles))) (get "/styles.css" (fn () (styles)))

View File

@ -145,6 +145,29 @@ static const char* errorText[] = {"MISMATCHED_PARENS",
"INDEX_PAST_END"}; "INDEX_PAST_END"};
#endif #endif
size_t inflate(struct string* s, size_t additional)
{
size_t length = (s->cursor - s->allocPoint) + additional;
int needsInflation = 0;
while (length > s->capacity - 8) {
s->capacity *= 2;
needsInflation = 1;
}
if (needsInflation) {
char* oldAlloc = s->allocPoint;
s->allocPoint = malloc(sizeof(char) * s->capacity);
size_t l = sprintf(s->allocPoint, "%s", oldAlloc);
s->cursor = s->allocPoint + l;
free(oldAlloc);
}
return s->capacity;
}
int stringNObj(struct string *s, const Object* obj);
/** /**
* Creates a string from a given list Object * Creates a string from a given list Object
* Blocks out with parens * Blocks out with parens
@ -152,52 +175,46 @@ static const char* errorText[] = {"MISMATCHED_PARENS",
* @param dest The string to copy the list text into * @param dest The string to copy the list text into
* @param obj The list Object to make a string from * @param obj The list Object to make a string from
*/ */
int stringList(char* dest, const Object* obj) void stringList(struct string* s, const Object* obj)
{ {
const char* initial = dest; s->cursor += sprintf(s->cursor, "(");
dest += sprintf(dest, "(");
FOR_POINTER_IN_LIST(obj) { FOR_POINTER_IN_LIST(obj) {
char tok[256] = ""; s->cursor += sprintf(s->cursor, " ");
stringObj(tok, POINTER); stringNObj(s, POINTER);
dest += sprintf(dest, " %s", tok); inflate(s, 0);
} }
dest += sprintf(dest, " )"); s->cursor += sprintf(s->cursor, " )");
return dest - initial;
} }
/** /**
* Creates a string from a given struct Object * Creates a string from a given struct Object
* Blocks out with curly braces * Blocks out with curly braces
*/ */
int stringStruct(char* dest, const Object* obj) void stringStruct(struct string* s, const Object* obj)
{ {
struct StructObject* so = obj->structObject; struct StructObject* so = obj->structObject;
const char* initial = dest; s->cursor += sprintf(s->cursor, "{");
dest += sprintf(dest, "{");
struct StructDef* def = getStructAt(so->definition); struct StructDef* def = getStructAt(so->definition);
for (int i = 0; i < def->fieldCount; i++) { for (int i = 0; i < def->fieldCount; i++) {
dest += sprintf(dest, " %s: ", def->names[i]); s->cursor += sprintf(s->cursor, " %s: ", def->names[i]);
int isString = so->fields[i].type == TYPE_STRING; int isString = so->fields[i].type == TYPE_STRING;
if (isString) { if (isString) {
dest += sprintf(dest, "\""); s->cursor += sprintf(s->cursor, "\"");
} }
char tok[90] = ""; stringNObj(s, &so->fields[i]);
stringObj(tok, &so->fields[i]);
dest += sprintf(dest, "%s", tok);
if (isString) { if (isString) {
dest += sprintf(dest, "\""); s->cursor += sprintf(s->cursor, "\"");
} }
dest += sprintf(dest, ","); s->cursor += sprintf(s->cursor, ",");
} }
dest--; s->cursor--;
dest += sprintf(dest, " }"); s->cursor += sprintf(s->cursor, " }");
return dest - initial;
} }
/** /**
* Creates a string from a given Object * Creates a string from a given Object
* Returns NULL if either param is NULL * Returns NULL if either param is NULL
@ -214,96 +231,90 @@ int stringStruct(char* dest, const Object* obj)
* @param dest The string to copy the list text into * @param dest The string to copy the list text into
* @param obj The list Object to make a string from * @param obj The list Object to make a string from
*/ */
#ifdef STANDALONE int stringNObj(struct string* s, const Object* obj)
#define stringf(_dest, _len, _format, args...) sprintf(_dest, _format, ## args)
#else
#define stringf(_dest, _len, _format, args...) snprintf(_dest, _len, _format, ## args)
#endif
int stringNObj(char* dest, const Object* obj, const size_t len)
{ {
const char* initial = dest; inflate(s, 16);
switch (obj->type) { switch (obj->type) {
case TYPE_NUMBER: case TYPE_NUMBER:
dest += stringf(dest, len, "%d", obj->number); s->cursor += sprintf(s->cursor, "%d", obj->number);
break; break;
case TYPE_BOOL: case TYPE_BOOL:
dest += stringf(dest, len, "%s", obj->number ? "T" : "F"); s->cursor += sprintf(s->cursor, "%s", obj->number ? "T" : "F");
break; break;
case TYPE_STRING: case TYPE_STRING: {
dest += stringf(dest, len, "%s", obj->string); size_t stringLen = strlen(obj->string);
inflate(s, stringLen);
s->cursor += sprintf(s->cursor, "%s", obj->string);
break; break;
}
case TYPE_SYMBOL: case TYPE_SYMBOL:
dest += stringf(dest, len, "`%s`", obj->string); s->cursor += sprintf(s->cursor, "`%s`", obj->string);
break; break;
case TYPE_STRUCT: case TYPE_STRUCT:
//snprintf(dest, len, "{%s}", obj->structObject->definition->names[0]); stringStruct(s, obj);
dest += stringStruct(dest, obj);
break; break;
case TYPE_LIST: case TYPE_LIST:
case TYPE_SLIST: case TYPE_SLIST:
dest += stringList(dest, obj); stringList(s, obj);
break; break;
case TYPE_ERROR: { case TYPE_ERROR: {
int code = getErrorCode(*obj); int code = getErrorCode(*obj);
#ifdef SIMPLE_ERRORS #ifdef SIMPLE_ERRORS
dest += stringf(dest, len, "E[%d]", (int)code); s->cursor += sprintf(s->cursor, "E[%d]", (int)code);
#else #else
inflate(s, 128);
if (obj->error->context && obj->error->context[0] != '\0') { if (obj->error->context && obj->error->context[0] != '\0') {
dest += stringf(dest, len, "%s: %s", errorText[code], s->cursor += sprintf(s->cursor, "%s: %s", errorText[code],
obj->error->context); obj->error->context);
} else if (code >= 0 && code <= INDEX_PAST_END) { } else if (code >= 0 && code <= INDEX_PAST_END) {
dest += stringf(dest, len, "%s", errorText[code]); s->cursor += sprintf(s->cursor, "%s", errorText[code]);
} else { } else {
dest += stringf(dest, len, "BROKEN ERROR CODE: %d", code); s->cursor += sprintf(s->cursor, "BROKEN ERROR CODE: %d", code);
} }
#endif #endif
break; break;
} }
case TYPE_FUNC: case TYPE_FUNC:
dest += stringf(dest, len, "F%d", obj->number); s->cursor += sprintf(s->cursor, "F%d", obj->number);
break; break;
case TYPE_LAMBDA: { case TYPE_LAMBDA: {
#ifdef STANDALONE #ifdef STANDALONE
#ifdef DEBUG #ifdef DEBUG
dest += stringf(dest, len, "\\x%d", obj->number); s->cursor += sprintf(s->cursor, len, "\\x%d", obj->number);
#endif #endif
dest += stringNObj(dest, &obj->lambda->params, len); stringNObj(s, &obj->lambda->params);
dest += sprintf(dest, " -> "); s->cursor += sprintf(s->cursor, " -> ");
dest += stringNObj(dest, &obj->lambda->body, len); stringNObj(s, &obj->lambda->body);
dest += sprintf(dest, ">"); s->cursor += sprintf(s->cursor, ">");
#else #else
dest += stringf(dest, len, "\\x%d", obj->number); s->cursor += sprintf(s->cursor, len, "\\x%d", obj->number);
#endif #endif
break; break;
} }
case TYPE_OTHER: case TYPE_OTHER:
dest += stringf(dest, len, "%p", obj->other->data); s->cursor += sprintf(s->cursor, "%p", obj->other->data);
break; break;
} }
if (!isValidType(*obj)) { if (!isValidType(*obj)) {
dest += stringf(dest, len, "BAD_TYPE(%d) X%d", obj->type, obj->number); s->cursor += sprintf(s->cursor, "BAD_TYPE(%d) X%d", obj->type, obj->number);
} }
return dest - initial; return 0;
} }
int stringObj(char* dest, const Object* obj) char* stringObj(const Object* obj, size_t* length)
{ {
return stringNObj(dest, obj, RESULT_LENGTH); char* alloc = malloc(8);
} struct string s = {
.allocPoint = alloc,
/** .cursor = alloc,
* Prints a given Object only if the DEBUG flag is set .capacity = 8,
* @param obj The Object to debug };
*/ s.allocPoint[0] = '\0';
void debugObj(const Object* obj) stringNObj(&s, obj);
{ *length = s.cursor - s.allocPoint;
#ifdef DEBUG return s.allocPoint;
printObj(obj);
#endif
} }
#if defined(DEBUG) || defined(STANDALONE) #if defined(DEBUG) || defined(STANDALONE)
@ -341,33 +352,28 @@ void printType(const Object* obj)
void _printObj(const Object* obj, int newline) void _printObj(const Object* obj, int newline)
{ {
#ifdef DEBUG
printType(obj);
#endif
if (!obj) { if (!obj) {
printf(newline ? "\n" : ""); printf(newline ? "\n" : "");
return; return;
} }
char temp[1024] = ""; size_t length;
stringNObj(temp, obj, 1024); char* temp = stringObj(obj, &length);
if (newline) { if (newline) {
printf("%s\n", temp); printf("%s\n", temp);
if (obj->type == TYPE_ERROR) { if (obj->type == TYPE_ERROR) {
if (obj->error && obj->error->plContext) { if (obj->error && obj->error->plContext) {
printf("%s\n", obj->error->plContext->text); printf("%s\n", obj->error->plContext->text);
return;
} }
} }
} else { } else {
printf("%s", temp); printf("%s", temp);
} }
free(temp);
} }
/** /**
* Prints the given Object and a newline. * Prints the given Object and a newline.
* Uses stringObj() to create the printed string * Uses stringObj() to create the printed string
* If the DEBUG flag is set, the Object's type will be printed first
* @param obj The Object to print * @param obj The Object to print
*/ */
inline void printObj(const Object* obj) inline void printObj(const Object* obj)

View File

@ -128,9 +128,13 @@ struct Other {
void* data; void* data;
}; };
int stringNObj(char* dest, const Object* obj, size_t len); struct string {
char* allocPoint;
char* cursor;
size_t capacity;
};
int stringObj(char* dest, const Object* obj); char* stringObj(const Object* obj, size_t* length);
void printType(const Object* obj); void printType(const Object* obj);

View File

@ -607,8 +607,8 @@ void repl(struct Environment* env)
} }
add_history(buf); add_history(buf);
Object o = parseEval(buf, env); Object o = parseEval(buf, env);
char output[1024]; size_t length;
stringNObj(output, &o, 1024); char *output = stringObj(&o, &length);
printColored(output); printColored(output);
printf("\n"); printf("\n");
cleanObject(&o); cleanObject(&o);

View File

@ -8,7 +8,7 @@ Object typeCheck(const char* funcName, Object* params, int length,
{ {
*failed = 1; *failed = 1;
if ((typeLength - 1) > length) { if ((typeLength - 1) > length) {
return errorObject(NOT_ENOUGH_ARGUMENTS); return errorWithContext(NOT_ENOUGH_ARGUMENTS, funcName);
} }
for (int i = 0; i < typeLength - 1; i++) { for (int i = 0; i < typeLength - 1; i++) {
if (typeChecks[i] && !typeChecks[i](params[i])) { // TODO: Use pl func name instead of C function name. if (typeChecks[i] && !typeChecks[i](params[i])) { // TODO: Use pl func name instead of C function name.
@ -235,16 +235,18 @@ Object _catObjects(Object obj1, Object obj2, struct Environment* env)
Object evalObj1 = eval(&obj1, env); Object evalObj1 = eval(&obj1, env);
Object evalObj2 = eval(&obj2, env); Object evalObj2 = eval(&obj2, env);
char str1[CAT_MAX] = ""; size_t length1;
char str2[CAT_MAX] = ""; size_t length2;
int length = stringObj(str1, &evalObj1); char* str1 = stringObj(&evalObj1, &length1);
length += stringObj(str2, &evalObj2); char* str2 = stringObj(&evalObj2, &length2);
cleanObject(&evalObj1); cleanObject(&evalObj1);
cleanObject(&evalObj2); cleanObject(&evalObj2);
Object o = withLen(length, TYPE_STRING); Object o = withLen(length1 + length2, TYPE_STRING);
sprintf(o.string, "%s%s", str1, str2); sprintf(o.string, "%s%s", str1, str2);
free(str1);
free(str2);
return o; return o;
} }

View File

@ -82,8 +82,8 @@ answer_to_connection(void* cls, struct MHD_Connection* connection,
Object queryParams = listObject(); Object queryParams = listObject();
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, add_query_param, &queryParams); MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, add_query_param, &queryParams);
Object res = numberObject(1010);//structObject(requestDefinition); Object res = structObject(requestDefinition);
//res.structObject->fields[0] = queryParams; res.structObject->fields[0] = queryParams;
Object route = cloneObject(routes[i].routeAction); Object route = cloneObject(routes[i].routeAction);
Object result = listEvalLambda(&route, &res, 2, routes[i].env); Object result = listEvalLambda(&route, &res, 2, routes[i].env);