#ifndef PEBBLISP_H #define PEBBLISP_H #include #include "env.h" #include "object.h" #define unused __attribute__((unused)) #define array_length(_array) (sizeof(_array) / sizeof((_array)[0])) #define UNPACK(...) __VA_ARGS__ #ifdef STANDALONE #define fnn(_name, _docs, ...) \ static const char * const _name ## Doc = _docs; \ unused static const char * const _name ## Tests[] = {__VA_ARGS__}; \ _Static_assert(array_length(_name ## Tests) % 2 == 0, "Array of test strings must have exactly one expected result for each test."); \ Object _name(Object* params, int length, struct Environment* env) struct TypeCheck { int (* checkFunc)(Object); const char* name; }; #define expect(_checker) {.checkFunc = (_checker), .name = #_checker} #define returns(_checker) {.checkFunc = (_checker), .name = #_checker} #define anyType {.checkFunc = NULL, .name = "AnyType"} #define tfn(_name, _symbol, _type, _docs, ...) \ unused static struct TypeCheck _name ## TypeChecks[] = UNPACK _type; \ static const char * const _name ## Symbol = _symbol; \ fnn(_name, _docs, __VA_ARGS__) #define fn(_name, _symbol, _docs, ...) \ static const char * const _name ## Symbol = _symbol; \ fnn(_name, _docs, __VA_ARGS__) #else #define fnn(_name, _docs, ...) \ Object _name(Object* params, int length, struct Environment* env) #define tfn(_name, _symbol, _type, _docs, ...) \ static const char * const _name ## Symbol = _symbol; \ fnn(_name, _docs, __VA_ARGS__) #define fn(_name, _symbol, _docs, ...) \ static const char * const _name ## Symbol = _symbol; \ fnn(_name, _docs, __VA_ARGS__) #endif #define trueObject() boolObject(1) #define falseObject() boolObject(0) struct Slice { const char* text; unsigned char length; int lineNumber; }; typedef struct Result { Object obj; struct Slice* slices; } Result; Object eval(const Object* obj, struct Environment* env); Result parse(struct Slice* slices); Result readSeq(struct Slice* slices); Result parseAtom(struct Slice* slice); Object parseEval(const char* input, struct Environment* env); Object evalList(const Object* obj, struct Environment* env); Object listEvalLambda(Object* lambda, const Object* passedArguments, int evalLength, struct Environment* env); Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength, struct Environment* env); Object simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment* env); Object typeCheck(const char* funcName, Object* params, int length, struct TypeCheck typeChecks[], int typeLength, int* failed); #ifndef STANDALONE #define DISABLE_TYPE_CHECKS #endif #ifndef DISABLE_TYPE_CHECKS #define checkTypes(FUNC) int FAILED; Object ERROR = typeCheck(FUNC ## Symbol, 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); int readFile(const char* filename, struct Environment* env); struct Slice* getLastOpen(); #endif /* STANDALONE */ tfn(mapO, "map", ({ expect(isFuncy), expect(isListy), returns(isListy) }), "Map over a list with a function.", "(map (fn (a) (* a a)) (1 2 3))", "( 1 4 9 )", ); fn(def, "def", "Define a variable in the current scope.", "(def x 10) x", "10", ); tfn(structAccess, "poss", ({ expect(isStruct), expect(isStringy), anyType }), "Get the value of a struct's field", "(struct Post (title body))\n " "(def p (Post \"This is a title\" \"This is the body\"))\n " "p.title", "This is a title" ); #endif