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:
parent
d2a0abeff3
commit
fb2e1811ff
|
@ -422,7 +422,7 @@ struct Environment defaultEnv()
|
|||
pf(isErr),
|
||||
pf(charVal),
|
||||
pf(parseEvalO),
|
||||
pf(possessive),
|
||||
pf(structAccess),
|
||||
pf(getTime),
|
||||
#ifndef LOW_MEM
|
||||
pf(reverse),
|
||||
|
|
|
@ -580,6 +580,11 @@ inline int isBool(const Object test)
|
|||
return test.type == TYPE_BOOL;
|
||||
}
|
||||
|
||||
inline int isStruct(const Object test)
|
||||
{
|
||||
return test.type == TYPE_STRUCT;
|
||||
}
|
||||
|
||||
inline int isFuncy(const Object test)
|
||||
{
|
||||
return test.type == TYPE_LAMBDA || test.type == TYPE_FUNC;
|
||||
|
|
|
@ -179,6 +179,8 @@ int isStringy(Object test);
|
|||
|
||||
int isBool(Object test);
|
||||
|
||||
int isStruct(Object test);
|
||||
|
||||
int isFuncy(Object test);
|
||||
|
||||
int isValidType(Object test);
|
||||
|
|
|
@ -314,23 +314,13 @@ Object eval(const Object* obj, struct Environment* env)
|
|||
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 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);
|
||||
for (int i = 0; i < structDef->fieldCount; i++) {
|
||||
if (strcmp(field.string, structDef->names[i]) == 0) {
|
||||
|
@ -467,14 +457,14 @@ Result parseAtom(struct Slice* s)
|
|||
} else if (c == '"'/* || c == '\''*/) {
|
||||
return (Result) { objFromSlice(s->text, s->length), s };
|
||||
} else if (s->text[s->length] == '.') {
|
||||
Object possessiveFunc = newObject(TYPE_FUNC);
|
||||
possessiveFunc.func = &possessive;
|
||||
Object list = startList(possessiveFunc);
|
||||
Object possesser = symFromSlice(s->text, s->length);
|
||||
nf_addToList(&list, possesser);
|
||||
Object structAccessFunc = newObject(TYPE_FUNC);
|
||||
structAccessFunc.func = &structAccess;
|
||||
Object list = startList(structAccessFunc);
|
||||
Object theStruct = symFromSlice(s->text, s->length);
|
||||
nf_addToList(&list, theStruct);
|
||||
struct Slice* next = s + 2;
|
||||
Object possessed = objFromSlice(&next->text[-1], next->length + 1);
|
||||
nf_addToList(&list, possessed);
|
||||
Object structField = objFromSlice(&next->text[-1], next->length + 1);
|
||||
nf_addToList(&list, structField);
|
||||
return (Result) { list, next };
|
||||
}
|
||||
return (Result) { symFromSlice(s->text, s->length), s };
|
||||
|
@ -536,6 +526,22 @@ Object parseEval(const char* input, struct Environment* env)
|
|||
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
|
||||
|
||||
int readFile(const char* filename, struct Environment* env)
|
||||
|
|
|
@ -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 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
|
||||
|
||||
int _readFile(FILE* input, struct Environment* env);
|
||||
|
@ -82,4 +94,12 @@ fn(def, "def",
|
|||
"(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
|
27
src/plfunc.c
27
src/plfunc.c
|
@ -3,31 +3,6 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
checkTypes(reduce)
|
||||
|
@ -377,7 +352,7 @@ Object numToChar(Object* params, int length, struct Environment* env)
|
|||
if (c.type != TYPE_NUMBER) {
|
||||
return errorObject(BAD_NUMBER);
|
||||
}
|
||||
char ch[1] = {c.number};
|
||||
char ch[1] = { c.number };
|
||||
return stringFromSlice(ch, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,14 +189,6 @@ fn(parseEvalO, "eval",
|
|||
"(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
|
||||
|
||||
fn(print, "prn", "Prints the string representation of the given object to stdout.");
|
||||
|
|
Loading…
Reference in New Issue