Wrote some small tests

This commit is contained in:
2022-08-28 09:35:46 +01:00
parent 71ff481f6c
commit f705d82aee
16 changed files with 605 additions and 529 deletions

View File

@@ -760,7 +760,7 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo
emitByte(&collation, &capacity, &count, TOY_VERSION_PATCH); emitByte(&collation, &capacity, &count, TOY_VERSION_PATCH);
//embed the build info //embed the build info
if (strlen(TOY_VERSION_BUILD) + count + 1 > capacity) { if ((int)strlen(TOY_VERSION_BUILD) + count + 1 > capacity) {
int oldCapacity = capacity; int oldCapacity = capacity;
capacity = strlen(TOY_VERSION_BUILD) + count + 1; //full header size capacity = strlen(TOY_VERSION_BUILD) + count + 1; //full header size
collation = GROW_ARRAY(unsigned char, collation, oldCapacity, capacity); collation = GROW_ARRAY(unsigned char, collation, oldCapacity, capacity);
@@ -808,7 +808,7 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo
Literal str = compiler->literalCache.literals[i]; Literal str = compiler->literalCache.literals[i];
for (int c = 0; c < STRLEN(str); c++) { for (int c = 0; c < (int)strlen(AS_STRING(str)); c++) {
emitByte(&collation, &capacity, &count, AS_STRING(str)[c]); emitByte(&collation, &capacity, &count, AS_STRING(str)[c]);
} }
@@ -885,7 +885,7 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo
Literal identifier = compiler->literalCache.literals[i]; Literal identifier = compiler->literalCache.literals[i];
for (int c = 0; c < STRLEN_I(identifier); c++) { for (int c = 0; c < (int)strlen(AS_IDENTIFIER(identifier)); c++) {
emitByte(&collation, &capacity, &count, AS_IDENTIFIER(identifier)[c]); emitByte(&collation, &capacity, &count, AS_IDENTIFIER(identifier)[c]);
} }

View File

@@ -26,7 +26,7 @@ bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func) {
return false; return false;
} }
Literal identifier = TO_IDENTIFIER_LITERAL(name); Literal identifier = TO_IDENTIFIER_LITERAL(copyString(name, strlen(name)), strlen(name));
//make sure the name isn't taken //make sure the name isn't taken
if (existsLiteralDictionary(&interpreter->scope->variables, identifier)) { if (existsLiteralDictionary(&interpreter->scope->variables, identifier)) {
@@ -99,10 +99,10 @@ int _set(Interpreter* interpreter, LiteralArray* arguments) {
//if it's a string or an identifier, make a local copy //if it's a string or an identifier, make a local copy
if (IS_STRING(val)) { if (IS_STRING(val)) {
val = TO_STRING_LITERAL(copyString(AS_STRING(val), STRLEN(val))); val = TO_STRING_LITERAL(copyString(AS_STRING(val), strlen(AS_STRING(val)) ), strlen(AS_STRING(val)));
} }
if (IS_IDENTIFIER(val)) { if (IS_IDENTIFIER(val)) {
val = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(val), STRLEN_I(val))); val = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(val), strlen(AS_IDENTIFIER(val)) ), strlen(AS_STRING(val)));
} }
//TODO: proper copy function for literals //TODO: proper copy function for literals
@@ -266,7 +266,7 @@ int _length(Interpreter* interpreter, LiteralArray* arguments) {
return 1; return 1;
case LITERAL_STRING: case LITERAL_STRING:
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( STRLEN(obj) )); pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( strlen(AS_STRING(obj)) ));
return 1; return 1;
default: default:
@@ -535,7 +535,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
//special case for string concatenation ONLY //special case for string concatenation ONLY
if (IS_STRING(lhs) && IS_STRING(rhs)) { if (IS_STRING(lhs) && IS_STRING(rhs)) {
//check for overflow //check for overflow
if (STRLEN(lhs) + STRLEN(rhs) > MAX_STRING_LENGTH) { if (strlen(AS_STRING(lhs)) + strlen(AS_STRING(rhs)) > MAX_STRING_LENGTH) {
printf(ERROR "ERROR: Can't concatenate these strings (result is too long)\n" RESET); printf(ERROR "ERROR: Can't concatenate these strings (result is too long)\n" RESET);
return false; return false;
} }
@@ -543,7 +543,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
//concat the strings //concat the strings
char buffer[MAX_STRING_LENGTH]; char buffer[MAX_STRING_LENGTH];
snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs)); snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs));
pushLiteralArray(&interpreter->stack, TO_STRING_LITERAL(buffer)); pushLiteralArray(&interpreter->stack, TO_STRING_LITERAL( copyString(buffer, strlen(buffer)), strlen(buffer) ));
return true; return true;
} }
@@ -823,19 +823,21 @@ static bool execValCast(Interpreter* interpreter) {
case LITERAL_STRING: case LITERAL_STRING:
if (IS_BOOLEAN(value)) { if (IS_BOOLEAN(value)) {
result = TO_STRING_LITERAL(AS_BOOLEAN(value) ? "true" : "false"); char* str = AS_BOOLEAN(value) ? "true" : "false";
result = TO_STRING_LITERAL(copyString(str, strlen(str)), strlen(str));
} }
if (IS_INTEGER(value)) { if (IS_INTEGER(value)) {
char buffer[128]; char buffer[128];
snprintf(buffer, 128, "%d", AS_INTEGER(value)); snprintf(buffer, 128, "%d", AS_INTEGER(value));
result = TO_STRING_LITERAL(buffer); result = TO_STRING_LITERAL(copyString(buffer, strlen(buffer)), strlen(buffer));
} }
if (IS_FLOAT(value)) { if (IS_FLOAT(value)) {
char buffer[128]; char buffer[128];
snprintf(buffer, 128, "%g", AS_FLOAT(value)); snprintf(buffer, 128, "%g", AS_FLOAT(value));
result = TO_STRING_LITERAL(buffer); result = TO_STRING_LITERAL(copyString(buffer, strlen(buffer)), strlen(buffer));
} }
break; break;
@@ -1496,7 +1498,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
case LITERAL_STRING: { case LITERAL_STRING: {
char* s = readString(interpreter->bytecode, &interpreter->count); char* s = readString(interpreter->bytecode, &interpreter->count);
pushLiteralArray(&interpreter->literalCache, TO_STRING_LITERAL(s)); pushLiteralArray(&interpreter->literalCache, TO_STRING_LITERAL( copyString(s, strlen(s)), strlen(s) ));
if (command.verbose) { if (command.verbose) {
printf("(string \"%s\")\n", s); printf("(string \"%s\")\n", s);
@@ -1571,7 +1573,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
case LITERAL_IDENTIFIER: { case LITERAL_IDENTIFIER: {
char* str = readString(interpreter->bytecode, &interpreter->count); char* str = readString(interpreter->bytecode, &interpreter->count);
Literal identifier = TO_IDENTIFIER_LITERAL(str); Literal identifier = TO_IDENTIFIER_LITERAL(copyString(str, strlen(str)), strlen(str));
pushLiteralArray(&interpreter->literalCache, identifier); pushLiteralArray(&interpreter->literalCache, identifier);

View File

@@ -2,6 +2,8 @@
#include "opcodes.h" #include "opcodes.h"
#include "literal.h"
#include "literal_util.h"
#include "literal_array.h" #include "literal_array.h"
#include "literal_dictionary.h" #include "literal_dictionary.h"
#include "scope.h" #include "scope.h"

View File

@@ -1,38 +1,9 @@
#include "literal.h" #include "literal.h"
#include "memory.h" #include "memory.h"
#include "literal_array.h"
#include "literal_dictionary.h"
#include "console_colors.h" #include "console_colors.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
//utils
static void stdoutWrapper(const char* output) {
fprintf(stdout, "%s", output);
}
//buffer the prints
static char* globalPrintBuffer = NULL;
static size_t globalPrintCapacity = 0;
static size_t globalPrintCount = 0;
//BUGFIX: string quotes shouldn't show when just printing strings, but should show when printing them as members of something else
static char quotes = 0; //set to 0 to not show string quotes
static void printToBuffer(const char* str) {
while (strlen(str) + globalPrintCount > globalPrintCapacity) {
int oldCapacity = globalPrintCapacity;
globalPrintCapacity = GROW_CAPACITY(globalPrintCapacity);
globalPrintBuffer = GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
}
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str);
globalPrintCount += strlen(str);
}
//hash util functions //hash util functions
static unsigned int hashString(const char* string, int length) { static unsigned int hashString(const char* string, int length) {
@@ -54,281 +25,14 @@ static unsigned int hash(unsigned int x) {
} }
//exposed functions //exposed functions
void printLiteral(Literal literal) {
printLiteralCustom(literal, stdoutWrapper);
}
void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
switch(literal.type) {
case LITERAL_NULL:
printFn("null");
break;
case LITERAL_BOOLEAN:
printFn(AS_BOOLEAN(literal) ? "true" : "false");
break;
case LITERAL_INTEGER: {
char buffer[256];
snprintf(buffer, 256, "%d", AS_INTEGER(literal));
printFn(buffer);
}
break;
case LITERAL_FLOAT: {
char buffer[256];
snprintf(buffer, 256, "%g", AS_FLOAT(literal));
printFn(buffer);
}
break;
case LITERAL_STRING: {
char buffer[MAX_STRING_LENGTH];
if (!quotes) {
snprintf(buffer, MAX_STRING_LENGTH, "%.*s", STRLEN(literal), AS_STRING(literal));
}
else {
snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, STRLEN(literal), AS_STRING(literal), quotes);
}
printFn(buffer);
}
break;
case LITERAL_ARRAY: {
LiteralArray* ptr = AS_ARRAY(literal);
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the contents to the global buffer
printToBuffer("[");
for (int i = 0; i < ptr->count; i++) {
quotes = '"';
printLiteralCustom(ptr->literals[i], printToBuffer);
if (i + 1 < ptr->count) {
printToBuffer(",");
}
}
printToBuffer("]");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
case LITERAL_DICTIONARY: {
LiteralDictionary* ptr = AS_DICTIONARY(literal);
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the contents to the global buffer
int delimCount = 0;
printToBuffer("[");
for (int i = 0; i < ptr->capacity; i++) {
if (IS_NULL(ptr->entries[i].key)) {
continue;
}
if (delimCount++ > 0) {
printToBuffer(",");
}
quotes = '"';
printLiteralCustom(ptr->entries[i].key, printToBuffer);
printToBuffer(":");
quotes = '"';
printLiteralCustom(ptr->entries[i].value, printToBuffer);
}
//empty dicts MUST have a ":" printed
if (ptr->count == 0) {
printToBuffer(":");
}
printToBuffer("]");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
//TODO: functions
case LITERAL_FUNCTION:
case LITERAL_FUNCTION_NATIVE:
printFn("(function)");
break;
case LITERAL_IDENTIFIER: {
char buffer[256];
snprintf(buffer, 256, "%.*s", STRLEN_I(literal), AS_IDENTIFIER(literal));
printFn(buffer);
}
break;
case LITERAL_TYPE: {
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the type correctly
printToBuffer("<");
switch(AS_TYPE(literal).typeOf) {
case LITERAL_NULL:
printToBuffer("null");
break;
case LITERAL_BOOLEAN:
printToBuffer("bool");
break;
case LITERAL_INTEGER:
printToBuffer("int");
break;
case LITERAL_FLOAT:
printToBuffer("float");
break;
case LITERAL_STRING:
printToBuffer("string");
break;
case LITERAL_ARRAY:
//print all in the array
printToBuffer("[");
for (int i = 0; i < AS_TYPE(literal).count; i++) {
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i], printToBuffer);
}
printToBuffer("]");
break;
case LITERAL_DICTIONARY:
printToBuffer("[");
for (int i = 0; i < AS_TYPE(literal).count; i += 2) {
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i], printToBuffer);
printToBuffer(":");
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i + 1], printToBuffer);
}
printToBuffer("]");
break;
case LITERAL_FUNCTION:
printToBuffer("function");
//TODO: how to print a function
break;
case LITERAL_IDENTIFIER:
printToBuffer("identifier");
break;
case LITERAL_TYPE:
printToBuffer("type");
break;
case LITERAL_ANY:
printToBuffer("any");
break;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in print type: %d\n" RESET, AS_TYPE(literal).typeOf);
}
//const (printed last)
if (AS_TYPE(literal).constant) {
printToBuffer(" const");
}
printToBuffer(">");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
case LITERAL_TYPE_INTERMEDIATE:
case LITERAL_FUNCTION_INTERMEDIATE:
printFn("Unprintable literal found");
break;
case LITERAL_ANY:
printFn("(any)");
break;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in print: %d\n" RESET, literal.type);
}
}
void freeLiteral(Literal literal) { void freeLiteral(Literal literal) {
if (IS_STRING(literal)) { if (IS_STRING(literal)) {
FREE_ARRAY(char, AS_STRING(literal), STRLEN(literal) + 1); FREE_ARRAY(char, AS_STRING(literal), literal.as.string.length);
return; return;
} }
//TODO: are these needed? I wish i had valgrind
// if (IS_ARRAY(literal)) {
// freeLiteralArray(((LiteralArray*)(AS_ARRAY(literal))));
// }
// if (IS_DICTIONARY(literal)) {
// freeLiteralDictionary(((LiteralDictionary*)(AS_DICTIONARY(literal))));
// }
if (IS_IDENTIFIER(literal)) { if (IS_IDENTIFIER(literal)) {
FREE_ARRAY(char, AS_IDENTIFIER(literal), STRLEN_I(literal) + 1); FREE_ARRAY(char, AS_IDENTIFIER(literal), literal.as.identifier.length);
return; return;
} }
@@ -353,8 +57,8 @@ bool _isTruthy(Literal x) {
return true; return true;
} }
Literal _toStringLiteral(char* str) { Literal _toStringLiteral(char* str, int length) {
return ((Literal){LITERAL_STRING, { .string.ptr = (char*)str, .string.length = strlen((char*)str) }}); return ((Literal){LITERAL_STRING, { .string.ptr = (char*)str, .string.length = length }});
} }
Literal _toIdentifierLiteral(char* str, int length) { Literal _toIdentifierLiteral(char* str, int length) {
@@ -375,188 +79,3 @@ Literal* _typePushSubtype(Literal* lit, Literal subtype) {
return &((Literal*)(AS_TYPE(*lit).subtypes))[ AS_TYPE(*lit).count - 1 ]; return &((Literal*)(AS_TYPE(*lit).subtypes))[ AS_TYPE(*lit).count - 1 ];
} }
char* copyString(char* original, int length) {
//make a local copy of the char array
char* buffer = ALLOCATE(char, length + 1);
strncpy(buffer, original, length);
buffer[length] = '\0';
return buffer;
}
bool literalsAreEqual(Literal lhs, Literal rhs) {
//utility for other things
if (lhs.type != rhs.type) {
// ints and floats are compatible
if ((IS_INTEGER(lhs) || IS_FLOAT(lhs)) && (IS_INTEGER(rhs) || IS_FLOAT(rhs))) {
if (IS_INTEGER(lhs)) {
return AS_INTEGER(lhs) + AS_FLOAT(rhs);
}
else {
return AS_FLOAT(lhs) + AS_INTEGER(rhs);
}
}
return false;
}
switch(lhs.type) {
case LITERAL_NULL:
return true; //can only be true because of the check above
case LITERAL_BOOLEAN:
return AS_BOOLEAN(lhs) == AS_BOOLEAN(rhs);
case LITERAL_INTEGER:
return AS_INTEGER(lhs) == AS_INTEGER(rhs);
case LITERAL_FLOAT:
return AS_FLOAT(lhs) == AS_FLOAT(rhs);
case LITERAL_STRING:
if (STRLEN(lhs) != STRLEN(rhs)) {
return false;
}
return !strncmp(AS_STRING(lhs), AS_STRING(rhs), STRLEN(lhs));
case LITERAL_ARRAY:
case LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array
//mismatched sizes
if (AS_ARRAY(lhs)->count != AS_ARRAY(rhs)->count) {
return false;
}
//mismatched elements (in order)
for (int i = 0; i < AS_ARRAY(lhs)->count; i++) {
if (!literalsAreEqual( AS_ARRAY(lhs)->literals[i], AS_ARRAY(rhs)->literals[i] )) {
return false;
}
}
return true;
case LITERAL_DICTIONARY:
//relatively slow, especially when nested
for (int i = 0; i < AS_DICTIONARY(lhs)->capacity; i++) {
if (!IS_NULL(AS_DICTIONARY(lhs)->entries[i].key)) { //only compare non-null keys
//check it exists in rhs
if (!existsLiteralDictionary(AS_DICTIONARY(rhs), AS_DICTIONARY(lhs)->entries[i].key)) {
return false;
}
//compare the values
if (!literalsAreEqual(AS_DICTIONARY(lhs)->entries[i].value, getLiteralDictionary(AS_DICTIONARY(rhs), AS_DICTIONARY(lhs)->entries[i].key) )) {
return false;
}
}
}
return true;
case LITERAL_FUNCTION:
case LITERAL_FUNCTION_NATIVE:
return false; //functions are never equal
break;
case LITERAL_IDENTIFIER:
//check shortcuts
if (HASH_I(lhs) != HASH_I(rhs) && STRLEN_I(lhs) != STRLEN_I(rhs)) {
return false;
}
return !strncmp(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs), STRLEN_I(lhs));
case LITERAL_TYPE:
//check types
if (AS_TYPE(lhs).typeOf != AS_TYPE(rhs).typeOf) {
return false;
}
//const don't match
if (AS_TYPE(lhs).constant != AS_TYPE(rhs).constant) {
return false;
}
//check subtypes
if (AS_TYPE(lhs).count != AS_TYPE(rhs).count) {
return false;
}
//check array|dictionary signatures are the same (in order)
if (AS_TYPE(lhs).typeOf == LITERAL_ARRAY || AS_TYPE(lhs).typeOf == LITERAL_DICTIONARY) {
for (int i = 0; i < AS_TYPE(lhs).count; i++) {
if (!literalsAreEqual(((Literal*)(AS_TYPE(lhs).subtypes))[i], ((Literal*)(AS_TYPE(rhs).subtypes))[i])) {
return false;
}
}
}
return true;
case LITERAL_ANY:
return true;
case LITERAL_FUNCTION_INTERMEDIATE:
fprintf(stderr, ERROR "[internal] Can't compare intermediate functions\n" RESET);
return false;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in equality: %d\n" RESET, lhs.type);
return false;
}
return false;
}
int hashLiteral(Literal lit) {
switch(lit.type) {
case LITERAL_NULL:
return 0;
case LITERAL_BOOLEAN:
return AS_BOOLEAN(lit) ? 1 : 0;
case LITERAL_INTEGER:
return hash((unsigned int)AS_INTEGER(lit));
case LITERAL_FLOAT:
return hash(*(unsigned int*)(&AS_FLOAT(lit)));
case LITERAL_STRING:
return hashString(AS_STRING(lit), STRLEN(lit));
case LITERAL_ARRAY: {
unsigned int res = 0;
for (int i = 0; i < AS_DICTIONARY(lit)->count; i++) {
res += hashLiteral(AS_ARRAY(lit)->literals[i]);
}
return hash(res);
}
case LITERAL_DICTIONARY: {
unsigned int res = 0;
for (int i = 0; i < AS_DICTIONARY(lit)->capacity; i++) {
if (!IS_NULL(AS_DICTIONARY(lit)->entries[i].key)) { //only hash non-null keys
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].key);
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].value);
}
}
return hash(res);
}
// case LITERAL_FUNCTION:
// //
case LITERAL_IDENTIFIER:
return HASH_I(lit); //pre-computed
// case LITERAL_TYPE:
// //not needed
// case LITERAL_ANY:
// //not needed
default:
//should never bee seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in hash: %d\n" RESET, lit.type);
return 0;
}
}

View File

@@ -86,33 +86,25 @@ typedef struct {
#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }}) #define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }})
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }}) #define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }})
#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }}) #define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }})
#define TO_STRING_LITERAL(value) _toStringLiteral(value) #define TO_STRING_LITERAL(value, l) _toStringLiteral(value, l)
#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }}) #define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }})
#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }}) #define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }})
#define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.ptr = value, .function.scope = NULL, .function.length = l }}) #define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.ptr = value, .function.scope = NULL, .function.length = l }})
#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value, strlen(value)) #define TO_IDENTIFIER_LITERAL(value, l) _toIdentifierLiteral(value, l)
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }}) #define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
//utils
void printLiteral(Literal literal);
void printLiteralCustom(Literal literal, void (printFn)(const char*));
void freeLiteral(Literal literal); void freeLiteral(Literal literal);
#define IS_TRUTHY(x) _isTruthy(x) #define IS_TRUTHY(x) _isTruthy(x)
#define MAX_STRING_LENGTH 4096 #define MAX_STRING_LENGTH 4096
#define STRLEN(lit) ((lit).as.string.length) // #define STRLEN(lit) ((lit).as.string.length)
#define STRLEN_I(lit) ((lit).as.identifier.length) // #define STRLEN_I(lit) ((lit).as.identifier.length)
#define HASH_I(lit) ((lit).as.identifier.hash) #define HASH_I(lit) ((lit).as.identifier.hash)
#define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype) #define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype)
//BUGFIX: macros are not functions //BUGFIX: macros are not functions
bool _isTruthy(Literal x); bool _isTruthy(Literal x);
Literal _toStringLiteral(char* str); Literal _toStringLiteral(char* str, int length);
Literal _toIdentifierLiteral(char* str, int length); Literal _toIdentifierLiteral(char* str, int length);
Literal* _typePushSubtype(Literal* lit, Literal subtype); Literal* _typePushSubtype(Literal* lit, Literal subtype);
//utils
char* copyString(char* original, int length);
bool literalsAreEqual(Literal lhs, Literal rhs);
int hashLiteral(Literal lit);

View File

@@ -22,10 +22,10 @@ int pushLiteralArray(LiteralArray* array, Literal literal) {
//if it's a string or an identifier, make a local copy //if it's a string or an identifier, make a local copy
if (IS_STRING(literal)) { if (IS_STRING(literal)) {
literal = TO_STRING_LITERAL(copyString(AS_STRING(literal), STRLEN(literal))); literal = TO_STRING_LITERAL(copyString(AS_STRING(literal), strlen( AS_STRING(literal) )), strlen( AS_STRING(literal) ));
} }
if (IS_IDENTIFIER(literal)) { if (IS_IDENTIFIER(literal)) {
literal = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(literal), STRLEN_I(literal))); literal = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(literal), strlen( AS_IDENTIFIER(literal) )), strlen( AS_IDENTIFIER(literal) ));
} }
array->literals[array->count] = literal; array->literals[array->count] = literal;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "literal.h" #include "literal.h"
#include "literal_util.h"
typedef struct LiteralArray { typedef struct LiteralArray {
Literal* literals; Literal* literals;

View File

@@ -15,12 +15,12 @@ static void setEntryValues(_entry* entry, Literal key, Literal value) {
//take ownership of the copied string //take ownership of the copied string
if (IS_STRING(key)) { if (IS_STRING(key)) {
entry->key = TO_STRING_LITERAL( copyString(AS_STRING(key), STRLEN(key)) ); entry->key = TO_STRING_LITERAL( copyString(AS_STRING(key), strlen(AS_STRING(key)) ), strlen(AS_STRING(key)));
} }
//OR take ownership of the copied identifier //OR take ownership of the copied identifier
else if (IS_IDENTIFIER(key)) { else if (IS_IDENTIFIER(key)) {
entry->key = TO_IDENTIFIER_LITERAL( copyString(AS_IDENTIFIER(key), STRLEN_I(key)) ); entry->key = TO_IDENTIFIER_LITERAL( copyString(AS_IDENTIFIER(key), strlen( AS_IDENTIFIER(key))), strlen(AS_IDENTIFIER(key)) );
} }
else { else {
@@ -33,10 +33,10 @@ static void setEntryValues(_entry* entry, Literal key, Literal value) {
//take ownership of the copied string //take ownership of the copied string
if (IS_STRING(value)) { if (IS_STRING(value)) {
char* buffer = ALLOCATE(char, STRLEN(value) + 1); char* buffer = ALLOCATE(char, strlen(AS_STRING(value)) + 1);
strncpy(buffer, AS_STRING(value), STRLEN(value)); strncpy(buffer, AS_STRING(value), strlen(AS_STRING(value)));
buffer[STRLEN(value)] = '\0'; buffer[strlen(AS_STRING(value))] = '\0';
entry->value = TO_STRING_LITERAL(buffer); entry->value = TO_STRING_LITERAL(buffer, strlen(buffer));
} }
//OR take ownership of the copied function //OR take ownership of the copied function
@@ -125,17 +125,17 @@ static bool setEntryArray(_entry** dictionaryHandle, int* capacityPtr, int conta
//if it's a string or an identifier, make a local copy //if it's a string or an identifier, make a local copy
if (IS_STRING(key)) { if (IS_STRING(key)) {
key = TO_STRING_LITERAL(copyString(AS_STRING(key), STRLEN(key))); key = TO_STRING_LITERAL(copyString(AS_STRING(key), strlen(AS_STRING(key)) ), strlen(AS_STRING(key)));
} }
if (IS_IDENTIFIER(key)) { if (IS_IDENTIFIER(key)) {
key = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(key), STRLEN_I(key))); key = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(key), strlen(AS_IDENTIFIER(key)) ), strlen(AS_IDENTIFIER(key)));
} }
if (IS_STRING(value)) { if (IS_STRING(value)) {
value = TO_STRING_LITERAL(copyString(AS_STRING(value), STRLEN(value))); key = TO_STRING_LITERAL(copyString(AS_STRING(value), strlen(AS_STRING(value)) ), strlen(AS_STRING(value)));
} }
if (IS_IDENTIFIER(value)) { if (IS_IDENTIFIER(value)) {
value = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(value), STRLEN_I(value))); key = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(value), strlen(AS_IDENTIFIER(value)) ), strlen(AS_IDENTIFIER(value)));
} }
//true = contains increase //true = contains increase

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "literal.h" #include "literal.h"
#include "literal_util.h"
//TODO: benchmark this //TODO: benchmark this
#define DICTIONARY_MAX_LOAD 0.75 #define DICTIONARY_MAX_LOAD 0.75

498
source/literal_util.c Normal file
View File

@@ -0,0 +1,498 @@
#include "literal_util.h"
#include "literal_array.h"
#include "literal_dictionary.h"
#include "memory.h"
#include "console_colors.h"
#include <stdio.h>
char* copyString(char* original, int length) {
//make a local copy of the char array
char* buffer = ALLOCATE(char, length + 1);
strncpy(buffer, original, length);
buffer[length] = '\0';
return buffer;
}
bool literalsAreEqual(Literal lhs, Literal rhs) {
//utility for other things
if (lhs.type != rhs.type) {
// ints and floats are compatible
if ((IS_INTEGER(lhs) || IS_FLOAT(lhs)) && (IS_INTEGER(rhs) || IS_FLOAT(rhs))) {
if (IS_INTEGER(lhs)) {
return AS_INTEGER(lhs) + AS_FLOAT(rhs);
}
else {
return AS_FLOAT(lhs) + AS_INTEGER(rhs);
}
}
return false;
}
switch(lhs.type) {
case LITERAL_NULL:
return true; //can only be true because of the check above
case LITERAL_BOOLEAN:
return AS_BOOLEAN(lhs) == AS_BOOLEAN(rhs);
case LITERAL_INTEGER:
return AS_INTEGER(lhs) == AS_INTEGER(rhs);
case LITERAL_FLOAT:
return AS_FLOAT(lhs) == AS_FLOAT(rhs);
case LITERAL_STRING:
if (strlen(AS_STRING(lhs)) != strlen(AS_STRING(rhs))) {
return false;
}
return !strncmp(AS_STRING(lhs), AS_STRING(rhs), strlen(AS_STRING(lhs)));
case LITERAL_ARRAY:
case LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array
//mismatched sizes
if (AS_ARRAY(lhs)->count != AS_ARRAY(rhs)->count) {
return false;
}
//mismatched elements (in order)
for (int i = 0; i < AS_ARRAY(lhs)->count; i++) {
if (!literalsAreEqual( AS_ARRAY(lhs)->literals[i], AS_ARRAY(rhs)->literals[i] )) {
return false;
}
}
return true;
case LITERAL_DICTIONARY:
//relatively slow, especially when nested
for (int i = 0; i < AS_DICTIONARY(lhs)->capacity; i++) {
if (!IS_NULL(AS_DICTIONARY(lhs)->entries[i].key)) { //only compare non-null keys
//check it exists in rhs
if (!existsLiteralDictionary(AS_DICTIONARY(rhs), AS_DICTIONARY(lhs)->entries[i].key)) {
return false;
}
//compare the values
if (!literalsAreEqual(AS_DICTIONARY(lhs)->entries[i].value, getLiteralDictionary(AS_DICTIONARY(rhs), AS_DICTIONARY(lhs)->entries[i].key) )) {
return false;
}
}
}
return true;
case LITERAL_FUNCTION:
case LITERAL_FUNCTION_NATIVE:
return false; //functions are never equal
break;
case LITERAL_IDENTIFIER:
//check shortcuts
if (HASH_I(lhs) != HASH_I(rhs) && strlen(AS_IDENTIFIER(lhs)) != strlen(AS_IDENTIFIER(rhs))) {
return false;
}
return !strncmp(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs), strlen( AS_IDENTIFIER(lhs) ));
case LITERAL_TYPE:
//check types
if (AS_TYPE(lhs).typeOf != AS_TYPE(rhs).typeOf) {
return false;
}
//const don't match
if (AS_TYPE(lhs).constant != AS_TYPE(rhs).constant) {
return false;
}
//check subtypes
if (AS_TYPE(lhs).count != AS_TYPE(rhs).count) {
return false;
}
//check array|dictionary signatures are the same (in order)
if (AS_TYPE(lhs).typeOf == LITERAL_ARRAY || AS_TYPE(lhs).typeOf == LITERAL_DICTIONARY) {
for (int i = 0; i < AS_TYPE(lhs).count; i++) {
if (!literalsAreEqual(((Literal*)(AS_TYPE(lhs).subtypes))[i], ((Literal*)(AS_TYPE(rhs).subtypes))[i])) {
return false;
}
}
}
return true;
case LITERAL_ANY:
return true;
case LITERAL_FUNCTION_INTERMEDIATE:
fprintf(stderr, ERROR "[internal] Can't compare intermediate functions\n" RESET);
return false;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in equality: %d\n" RESET, lhs.type);
return false;
}
return false;
}
//hash util functions
static unsigned int hashString(const char* string, int length) {
unsigned int hash = 2166136261u;
for (int i = 0; i < length; i++) {
hash *= string[i];
hash *= 16777619;
}
return hash;
}
static unsigned int hash(unsigned int x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
int hashLiteral(Literal lit) {
switch(lit.type) {
case LITERAL_NULL:
return 0;
case LITERAL_BOOLEAN:
return AS_BOOLEAN(lit) ? 1 : 0;
case LITERAL_INTEGER:
return hash((unsigned int)AS_INTEGER(lit));
case LITERAL_FLOAT:
return hash(*(unsigned int*)(&AS_FLOAT(lit)));
case LITERAL_STRING:
return hashString(AS_STRING(lit), strlen(AS_STRING(lit)));
case LITERAL_ARRAY: {
unsigned int res = 0;
for (int i = 0; i < AS_DICTIONARY(lit)->count; i++) {
res += hashLiteral(AS_ARRAY(lit)->literals[i]);
}
return hash(res);
}
case LITERAL_DICTIONARY: {
unsigned int res = 0;
for (int i = 0; i < AS_DICTIONARY(lit)->capacity; i++) {
if (!IS_NULL(AS_DICTIONARY(lit)->entries[i].key)) { //only hash non-null keys
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].key);
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].value);
}
}
return hash(res);
}
// case LITERAL_FUNCTION:
// //
case LITERAL_IDENTIFIER:
return HASH_I(lit); //pre-computed
// case LITERAL_TYPE:
// //not needed
// case LITERAL_ANY:
// //not needed
default:
//should never bee seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in hash: %d\n" RESET, lit.type);
return 0;
}
}
//utils
static void stdoutWrapper(const char* output) {
fprintf(stdout, "%s", output);
}
//buffer the prints
static char* globalPrintBuffer = NULL;
static size_t globalPrintCapacity = 0;
static size_t globalPrintCount = 0;
//BUGFIX: string quotes shouldn't show when just printing strings, but should show when printing them as members of something else
static char quotes = 0; //set to 0 to not show string quotes
static void printToBuffer(const char* str) {
while (strlen(str) + globalPrintCount > globalPrintCapacity) {
int oldCapacity = globalPrintCapacity;
globalPrintCapacity = GROW_CAPACITY(globalPrintCapacity);
globalPrintBuffer = GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
}
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str);
globalPrintCount += strlen(str);
}
//exposed functions
void printLiteral(Literal literal) {
printLiteralCustom(literal, stdoutWrapper);
}
void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
switch(literal.type) {
case LITERAL_NULL:
printFn("null");
break;
case LITERAL_BOOLEAN:
printFn(AS_BOOLEAN(literal) ? "true" : "false");
break;
case LITERAL_INTEGER: {
char buffer[256];
snprintf(buffer, 256, "%d", AS_INTEGER(literal));
printFn(buffer);
}
break;
case LITERAL_FLOAT: {
char buffer[256];
snprintf(buffer, 256, "%g", AS_FLOAT(literal));
printFn(buffer);
}
break;
case LITERAL_STRING: {
char buffer[MAX_STRING_LENGTH];
if (!quotes) {
snprintf(buffer, MAX_STRING_LENGTH, "%.*s", (int)strlen(AS_STRING(literal)), AS_STRING(literal));
}
else {
snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, (int)strlen(AS_STRING(literal)), AS_STRING(literal), quotes);
}
printFn(buffer);
}
break;
case LITERAL_ARRAY: {
LiteralArray* ptr = AS_ARRAY(literal);
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the contents to the global buffer
printToBuffer("[");
for (int i = 0; i < ptr->count; i++) {
quotes = '"';
printLiteralCustom(ptr->literals[i], printToBuffer);
if (i + 1 < ptr->count) {
printToBuffer(",");
}
}
printToBuffer("]");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
case LITERAL_DICTIONARY: {
LiteralDictionary* ptr = AS_DICTIONARY(literal);
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the contents to the global buffer
int delimCount = 0;
printToBuffer("[");
for (int i = 0; i < ptr->capacity; i++) {
if (IS_NULL(ptr->entries[i].key)) {
continue;
}
if (delimCount++ > 0) {
printToBuffer(",");
}
quotes = '"';
printLiteralCustom(ptr->entries[i].key, printToBuffer);
printToBuffer(":");
quotes = '"';
printLiteralCustom(ptr->entries[i].value, printToBuffer);
}
//empty dicts MUST have a ":" printed
if (ptr->count == 0) {
printToBuffer(":");
}
printToBuffer("]");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
//TODO: functions
case LITERAL_FUNCTION:
case LITERAL_FUNCTION_NATIVE:
printFn("(function)");
break;
case LITERAL_IDENTIFIER: {
char buffer[256];
snprintf(buffer, 256, "%.*s", (int)strlen( AS_IDENTIFIER(literal) ), AS_IDENTIFIER(literal));
printFn(buffer);
}
break;
case LITERAL_TYPE: {
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the type correctly
printToBuffer("<");
switch(AS_TYPE(literal).typeOf) {
case LITERAL_NULL:
printToBuffer("null");
break;
case LITERAL_BOOLEAN:
printToBuffer("bool");
break;
case LITERAL_INTEGER:
printToBuffer("int");
break;
case LITERAL_FLOAT:
printToBuffer("float");
break;
case LITERAL_STRING:
printToBuffer("string");
break;
case LITERAL_ARRAY:
//print all in the array
printToBuffer("[");
for (int i = 0; i < AS_TYPE(literal).count; i++) {
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i], printToBuffer);
}
printToBuffer("]");
break;
case LITERAL_DICTIONARY:
printToBuffer("[");
for (int i = 0; i < AS_TYPE(literal).count; i += 2) {
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i], printToBuffer);
printToBuffer(":");
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i + 1], printToBuffer);
}
printToBuffer("]");
break;
case LITERAL_FUNCTION:
printToBuffer("function");
//TODO: how to print a function
break;
case LITERAL_IDENTIFIER:
printToBuffer("identifier");
break;
case LITERAL_TYPE:
printToBuffer("type");
break;
case LITERAL_ANY:
printToBuffer("any");
break;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in print type: %d\n" RESET, AS_TYPE(literal).typeOf);
}
//const (printed last)
if (AS_TYPE(literal).constant) {
printToBuffer(" const");
}
printToBuffer(">");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
case LITERAL_TYPE_INTERMEDIATE:
case LITERAL_FUNCTION_INTERMEDIATE:
printFn("Unprintable literal found");
break;
case LITERAL_ANY:
printFn("(any)");
break;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in print: %d\n" RESET, literal.type);
}
}

10
source/literal_util.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "literal.h"
char* copyString(char* original, int length);
bool literalsAreEqual(Literal lhs, Literal rhs);
int hashLiteral(Literal lit);
void printLiteral(Literal literal);
void printLiteralCustom(Literal literal, void (printFn)(const char*));

View File

@@ -20,7 +20,7 @@ void* reallocate(void* pointer, size_t oldSize, size_t newSize) {
void* mem = realloc(pointer, newSize); void* mem = realloc(pointer, newSize);
if (mem == NULL) { if (mem == NULL) {
fprintf(stderr, ERROR "[internal]Memory allocation error (requested %d for %d, replacing %d)\n" ERROR, (int)newSize, (int)pointer, (int)oldSize); fprintf(stderr, ERROR "[internal]Memory allocation error (requested %d for %ld, replacing %d)\n" ERROR, (int)newSize, (long int)pointer, (int)oldSize);
exit(-1); exit(-1);
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "literal.h" #include "literal.h"
#include "literal_util.h" //TODO: move this to node_util.h
#include "opcodes.h" #include "opcodes.h"
#include "token_types.h" #include "token_types.h"

View File

@@ -255,7 +255,7 @@ static Opcode string(Parser* parser, Node** nodeHandle) {
error(parser, parser->previous, buffer); error(parser, parser->previous, buffer);
} }
emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, length))); emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, length), length));
return OP_EOF; return OP_EOF;
} }

View File

@@ -12,7 +12,7 @@ OBJ = $(addprefix $(ODIR)/,$(TARGETS:../source/%.c=%.o)) $(addprefix $(ODIR)/,$(
all: $(OBJ) $(TESTS:%.c=../$(OUTDIR)/%.exe) all: $(OBJ) $(TESTS:%.c=../$(OUTDIR)/%.exe)
../$(OUTDIR)/%.exe: $(ODIR)/%.o ../$(OUTDIR)/%.exe: $(ODIR)/%.o
$(CC) -o $@ $< $(TARGETS:../source/%.c=$(ODIR)/%.o) $(CFLAGS) $(LIBS) @$(CC) -o $@ $< $(TARGETS:../source/%.c=$(ODIR)/%.o) $(CFLAGS) $(LIBS)
$@ $@
$(OBJ): | $(ODIR) $(OBJ): | $(ODIR)
@@ -21,10 +21,10 @@ $(ODIR):
mkdir $(ODIR) mkdir $(ODIR)
$(ODIR)/%.o: %.c $(ODIR)/%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS) @$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/%.o: ../source/%.c $(ODIR)/%.o: ../source/%.c
$(CC) -c -o $@ $< $(CFLAGS) @$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean .PHONY: clean

50
test/test_literal.c Normal file
View File

@@ -0,0 +1,50 @@
#include "literal.h"
#include "memory.h"
#include "console_colors.h"
#include <stdio.h>
int main() {
{
//test a single null literal
Literal literal = TO_NULL_LITERAL;
//
if (!IS_NULL(literal)) {
fprintf(stderr, ERROR "ERROR: null literal failed\n" RESET);
return -1;
}
}
{
//test boolean literals
Literal t = TO_BOOLEAN_LITERAL(true);
Literal f = TO_BOOLEAN_LITERAL(false);
//
if (!IS_TRUTHY(t) || IS_TRUTHY(f)) {
fprintf(stderr, ERROR "ERROR: boolean literal failed\n" RESET);
return -1;
}
}
{
char* buffer = ALLOCATE(char, 128);
snprintf(buffer, 128, "Hello world");
Literal literal = TO_STRING_LITERAL(buffer, 128);
freeLiteral(literal);
}
//check allocated memory
if (getAllocatedMemoryCount() != 0) {
fprintf(stderr, ERROR "ERROR: Dangling memory detected: %d byes\n" RESET, getAllocatedMemoryCount());
return -1;
}
printf(NOTICE "All good\n" RESET);
return 0;
}