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(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),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
27
src/plfunc.c
27
src/plfunc.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
Loading…
Reference in New Issue