Rename possessive to structAccess.

Gives better error messages.
Use typical type-checking in structAccess.
Make checkTypes() more global, and move to pebblisp.c
This commit is contained in:
Sage Vaillancourt 2022-03-31 12:09:16 -04:00 committed by Sage Vaillancourt
parent d2a0abeff3
commit fb2e1811ff
7 changed files with 55 additions and 55 deletions

View File

@ -422,7 +422,7 @@ struct Environment defaultEnv()
pf(isErr), pf(isErr),
pf(charVal), pf(charVal),
pf(parseEvalO), pf(parseEvalO),
pf(possessive), pf(structAccess),
pf(getTime), pf(getTime),
#ifndef LOW_MEM #ifndef LOW_MEM
pf(reverse), pf(reverse),

View File

@ -580,6 +580,11 @@ inline int isBool(const Object test)
return test.type == TYPE_BOOL; return test.type == TYPE_BOOL;
} }
inline int isStruct(const Object test)
{
return test.type == TYPE_STRUCT;
}
inline int isFuncy(const Object test) inline int isFuncy(const Object test)
{ {
return test.type == TYPE_LAMBDA || test.type == TYPE_FUNC; return test.type == TYPE_LAMBDA || test.type == TYPE_FUNC;

View File

@ -179,6 +179,8 @@ int isStringy(Object test);
int isBool(Object test); int isBool(Object test);
int isStruct(Object test);
int isFuncy(Object test); int isFuncy(Object test);
int isValidType(Object test); int isValidType(Object test);

View File

@ -314,23 +314,13 @@ Object eval(const Object* obj, struct Environment* env)
return errorObject(BAD_TYPE); return errorObject(BAD_TYPE);
} }
Object possessive(Object* params, int length, struct Environment* env) Object structAccess(Object* params, int length, struct Environment* env)
{ {
checkTypes(structAccess)
Object structo = params[0]; Object structo = params[0];
Object field = params[1]; Object field = params[1];
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 = getStructAt(structo.structObject->definition); struct StructDef* structDef = getStructAt(structo.structObject->definition);
for (int i = 0; i < structDef->fieldCount; i++) { for (int i = 0; i < structDef->fieldCount; i++) {
if (strcmp(field.string, structDef->names[i]) == 0) { if (strcmp(field.string, structDef->names[i]) == 0) {
@ -467,14 +457,14 @@ Result parseAtom(struct Slice* s)
} else if (c == '"'/* || c == '\''*/) { } else if (c == '"'/* || c == '\''*/) {
return (Result) { objFromSlice(s->text, s->length), s }; return (Result) { objFromSlice(s->text, s->length), s };
} else if (s->text[s->length] == '.') { } else if (s->text[s->length] == '.') {
Object possessiveFunc = newObject(TYPE_FUNC); Object structAccessFunc = newObject(TYPE_FUNC);
possessiveFunc.func = &possessive; structAccessFunc.func = &structAccess;
Object list = startList(possessiveFunc); Object list = startList(structAccessFunc);
Object possesser = symFromSlice(s->text, s->length); Object theStruct = symFromSlice(s->text, s->length);
nf_addToList(&list, possesser); nf_addToList(&list, theStruct);
struct Slice* next = s + 2; struct Slice* next = s + 2;
Object possessed = objFromSlice(&next->text[-1], next->length + 1); Object structField = objFromSlice(&next->text[-1], next->length + 1);
nf_addToList(&list, possessed); nf_addToList(&list, structField);
return (Result) { list, next }; return (Result) { list, next };
} }
return (Result) { symFromSlice(s->text, s->length), s }; return (Result) { symFromSlice(s->text, s->length), s };
@ -536,6 +526,22 @@ Object parseEval(const char* input, struct Environment* env)
return obj; return obj;
} }
Object typeCheck(const char* funcName, Object* params, int length,
int (* typeChecks[])(Object), int typeLength, int* failed)
{
*failed = 1;
if ((typeLength - 1) > length) {
return errorWithContext(NOT_ENOUGH_ARGUMENTS, funcName);
}
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.
return /*errorObject(BAD_TYPE); */ errorWithContextLineNo(BAD_PARAMS_ON, funcName, 0, NULL);
}
}
*failed = 0;
return numberObject(0);
}
#ifdef STANDALONE #ifdef STANDALONE
int readFile(const char* filename, struct Environment* env) int readFile(const char* filename, struct Environment* env)

View File

@ -64,6 +64,18 @@ Object listEvalLambda(Object* lambda, const Object* remaining, int evalLength,
Object simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment* env); Object simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment* env);
Object typeCheck(const char* funcName, Object* params, int length,
int (* typeChecks[])(Object), int typeLength, int* failed);
#ifndef DISABLE_TYPE_CHECKS
#define checkTypes(FUNC) int FAILED; Object ERROR = typeCheck(#FUNC, params, length, FUNC ## TypeChecks, array_length(FUNC ## TypeChecks), &FAILED); \
if (FAILED) { \
return ERROR; \
}
#else
#define checkTypes(FUNC) ;
#endif
#ifdef STANDALONE #ifdef STANDALONE
int _readFile(FILE* input, struct Environment* env); int _readFile(FILE* input, struct Environment* env);
@ -82,4 +94,12 @@ fn(def, "def",
"(def x 10) x", "10", "(def x 10) x", "10",
); );
tfn(structAccess, "poss",
({ isStruct, isStringy, NULL }),
"Get the value of a struct's field",
"(struct Post (title body))\n "
"(def p (Post \"TI\" \"BO\"))\n "
"p.title", "TI"
);
#endif #endif

View File

@ -3,31 +3,6 @@
#include "plfunc.h" #include "plfunc.h"
Object typeCheck(const char* funcName, Object* params, int length,
int (* typeChecks[])(Object), int typeLength, int* failed)
{
*failed = 1;
if ((typeLength - 1) > length) {
return errorWithContext(NOT_ENOUGH_ARGUMENTS, funcName);
}
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.
return /*errorObject(BAD_TYPE); */ errorWithContextLineNo(BAD_PARAMS_ON, funcName, 0, NULL);
}
}
*failed = 0;
return numberObject(0);
}
#ifndef DISABLE_TYPE_CHECKS
#define checkTypes(FUNC) int FAILED; Object ERROR = typeCheck(#FUNC, params, length, FUNC ## TypeChecks, array_length(FUNC ## TypeChecks), &FAILED); \
if (FAILED) { \
return ERROR; \
}
#else
#define checkTypes(FUNC) ;
#endif
Object reduce(Object* params, int length, struct Environment* env) Object reduce(Object* params, int length, struct Environment* env)
{ {
checkTypes(reduce) checkTypes(reduce)
@ -377,7 +352,7 @@ Object numToChar(Object* params, int length, struct Environment* env)
if (c.type != TYPE_NUMBER) { if (c.type != TYPE_NUMBER) {
return errorObject(BAD_NUMBER); return errorObject(BAD_NUMBER);
} }
char ch[1] = {c.number}; char ch[1] = { c.number };
return stringFromSlice(ch, 1); return stringFromSlice(ch, 1);
} }

View File

@ -189,14 +189,6 @@ fn(parseEvalO, "eval",
"(eval '(+ 5 5))", "10", "(eval '(+ 5 5))", "10",
); );
/// STRUCT, STRING => ANY
fn(possessive, "poss",
"Get the value of a struct's field",
"(struct Post (title body))\n "
"(def p (Post \"TI\" \"BO\"))\n "
"p.title", "TI"
);
#ifdef STANDALONE #ifdef STANDALONE
fn(print, "prn", "Prints the string representation of the given object to stdout."); fn(print, "prn", "Prints the string representation of the given object to stdout.");