#ifndef OBJECT_H #define OBJECT_H #include #ifndef STANDALONE #include #undef sprintf #define sprintf(_dest, args...) snprintf(_dest, 999, args) #else #define ERR_LEN 256 #ifdef DEBUG #define printd(...) printf(__VA_ARGS__) #else #define printd(...) do { } while (0) #define eprintf(...) fprintf(stderr, __VA_ARGS__) #endif #endif #define MAX_TOK_CNT 1024 #define RESULT_LENGTH 128 #define FOR_POINTER_IN_LIST(_list) \ for(Object *_element = (_list)->list; \ _element != NULL;\ _element = _element->forward) #define POINTER _element #define BuildListNamed(LIST) Object LIST = listObject(); Object** LIST ## _LIST_ITEM = &(LIST.list) #define addToList(LIST, OBJECT) allocObject(LIST ## _LIST_ITEM, OBJECT); LIST ## _LIST_ITEM = &(*LIST ## _LIST_ITEM)->forward #ifdef PBL_PLATFORM_APLITE #define LOW_MEM #endif #ifdef LOW_MEM #define SIMPLE_ERRORS #endif #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) #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 enum errorCode { MISMATCHED_PARENS, NULL_ENV, EMPTY_ENV, NULL_PARSE, NULL_LAMBDA_LIST, NULL_MAP_ARGS, LAMBDA_ARGS_NOT_LIST, DID_NOT_FIND_SYMBOL, BAD_TYPE, BAD_PARAMS, BAD_NUMBER, UNSUPPORTED_NUMBER_TYPE, NOT_ENOUGH_ARGUMENTS, NOT_A_LIST, SCRIPT_NOT_FOUND, NO_CLONE_SPECIFIED, CAN_ONLY_EVAL_STRINGS, UNEXPECTED_EOF, INDEX_PAST_END, }; typedef enum Type { TYPE_NUMBER, TYPE_BOOL, TYPE_LIST, TYPE_SLIST, TYPE_STRUCT, TYPE_FUNC, TYPE_STATIC_FUNC, TYPE_SYMBOL, TYPE_LAMBDA, TYPE_STRING, TYPE_HASH_TABLE, TYPE_PROMISE, TYPE_OTHER, TYPE_ERROR } Type; typedef struct Object Object; struct Lambda; struct Environment; struct Promise; struct Other; struct StaticFunction; struct ObjectTableObject; struct Error { enum errorCode code; char* context; struct Slice* plContext; }; struct Object { Type type; union { long number; Object* list; char* string; Object (* func)(Object*, int, struct Environment*); struct StructObject* structObject; struct Lambda* lambda; struct StaticFunction* staticF; struct Other* other; struct Promise* promise; struct ObjectTableObject* table; #ifdef SIMPLE_ERRORS enum errorCode error; #else struct Error* error; #endif void* data; }; union { Object* forward; char* docString; }; }; struct StructDef { int fieldCount; char* name; char** names; }; struct StructObject { int definition; struct Object* fields; // Order should match that in the definition. }; struct Lambda { int refs; /// Note: params.docstring can contain details about the constructed lambda. Object params; Object body; }; struct StaticFunction { Object (* func)(Object*, int, struct Environment*); Object* arguments; int argCount; int refs; }; struct Other { void (* cleanup)(Object*); Object (* clone)(struct Other*); void* data; }; struct string { char* allocPoint; char* cursor; size_t capacity; }; const char* getTypeName(const Object* obj); /** * Returns a dynamically-sized string representation of the given object. * * _Adds_ the length of the new string to the `length` parameter. */ char* stringObj(const Object* obj, size_t* length); const char* getTypeName(const Object* obj); void printObj(const Object* obj); void _printObj(const Object* obj, int newline); void debugObj(const Object* obj); int isEmpty(const Object* obj); Object* tail(const Object* listObj); Object* nf_addToList(Object* dest, Object src); void deleteList(Object* dest); int listLength(const Object* listObj); Object* itemAt(const Object* listObj, int n); Object copyList(const Object* src); void cleanObject(Object* target); void printAndClean(Object* target); void allocObject(Object** spot, Object src); void appendList(Object* dest, const Object* src); int isNumber(Object test); int isListy(Object test); int isStringy(Object test); int isBool(Object test); int isStruct(Object test); int isFuncy(Object test); int isValidType(Object test); int isError(Object obj, enum errorCode err); int bothAre(enum Type type, const Object* obj1, const Object* obj2); int areSameType(const Object* obj1, const Object* obj2); Object cloneList(Object src); Object cloneString(Object obj); Object cloneLambda(Object old); Object cloneObject(Object src); Object newObject(Type type); Object listObject(); Object startList(Object start); Object objFromSlice(const char* string, int len); Object nullTerminated(const char* string); Object stringFromSlice(const char* string, int len); Object symFromSlice(const char* string, int len); Object withLen(size_t len, enum Type type); Object boolObject(int b); Object numberObject(int num); Object structObject(int definition); Object otherObject(); Object errorObject(enum errorCode err); #ifdef SIMPLE_ERRORS #define getErrorCode(OBJ) ((OBJ).error) #else #define getErrorCode(OBJ) ((OBJ).error->code) #endif Object errorWithContextLineNo(enum errorCode code, const char* context, int lineNo, const char* fileName); Object errorWithAllocatedContextLineNo(enum errorCode code, char* context, int lineNo, const char* fileName); #ifdef SIMPLE_ERRORS #define errorWithContext(code, context) errorObject(code) #define errorAddContext(x, y, z, a) ; #define throw(_code, ...) return errorObject(_code) #else #define throw(_code, ...) do { char* ERROR_CONTEXT = malloc(sizeof(char) * ERR_LEN); sprintf(ERROR_CONTEXT, __VA_ARGS__); \ return errorWithAllocatedContextLineNo(_code, ERROR_CONTEXT, __LINE__, __FILE__); } while (0) #define errorWithContext(_code, _context) errorWithContextLineNo(_code, _context, __LINE__, __FILE__) #endif struct Error noError(); Object constructLambda(const Object* params, const Object* docs, const Object* body, struct Environment* env); #ifdef STANDALONE int getAllocations(); size_t getBytes(); void* scalloc(size_t size, size_t count); void* smalloc(size_t size); #define malloc(x) smalloc(x) #define calloc(x, y) scalloc(x, y) #endif // STANDALONE #endif