diff --git a/makefile b/makefile index 5d695c6..fc76689 100644 --- a/makefile +++ b/makefile @@ -20,13 +20,14 @@ ifeq ($(findstring CYGWIN, $(shell uname)),CYGWIN) find . -type f -name '*.lib' -exec rm -f -r -v {} \; find . -type f -name '*.so' -exec rm -f -r -v {} \; find . -empty -type d -delete -else ifeq ($(shell uname), Linux) +else ifeq ($(shell uname),Linux) find . -type f -name '*.o' -exec rm -f -r -v {} \; find . -type f -name '*.a' -exec rm -f -r -v {} \; find . -type f -name '*.exe' -exec rm -f -r -v {} \; find . -type f -name '*.dll' -exec rm -f -r -v {} \; find . -type f -name '*.lib' -exec rm -f -r -v {} \; find . -type f -name '*.so' -exec rm -f -r -v {} \; + rm -rf out find . -empty -type d -delete else ifeq ($(OS),Windows_NT) $(RM) *.o *.a *.exe @@ -34,4 +35,4 @@ else @echo "Deletion failed - what platform is this?" endif -rebuild: clean all \ No newline at end of file +rebuild: clean all diff --git a/source/compiler.c b/source/compiler.c index 8f0b2e9..d2926c9 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -855,7 +855,7 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo case LITERAL_FUNCTION_INTERMEDIATE: { //extract the compiler Literal fn = compiler->literalCache.literals[i]; - void* fnCompiler = AS_FUNCTION(fn); + void* fnCompiler = AS_FUNCTION(fn).bytecode; //store the compiler here for now //collate the function into bytecode (without header) int size = 0; diff --git a/source/interpreter.c b/source/interpreter.c index 291100e..549be87 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -335,23 +335,6 @@ void initInterpreter(Interpreter* interpreter) { } void freeInterpreter(Interpreter* interpreter) { - //since these are dynamically allocated, free them manually - for (int i = 0; i < interpreter->literalCache.count; i++) { - if (IS_ARRAY(interpreter->literalCache.literals[i]) || IS_DICTIONARY(interpreter->literalCache.literals[i]) || IS_TYPE(interpreter->literalCache.literals[i])) { - - if (IS_TYPE(interpreter->literalCache.literals[i]) && AS_TYPE(interpreter->literalCache.literals[i]).capacity > 0) { - FREE_ARRAY(Literal, AS_TYPE(interpreter->literalCache.literals[i]).subtypes, AS_TYPE(interpreter->literalCache.literals[i]).capacity); - } - - freeLiteral(interpreter->literalCache.literals[i]); - - interpreter->literalCache.literals[i] = TO_NULL_LITERAL; - } - - if (IS_FUNCTION(interpreter->literalCache.literals[i])) { - FREE_ARRAY(unsigned char, interpreter->literalCache.literals[i].as.function.ptr, interpreter->literalCache.literals[i].as.function.length); - } - } freeLiteralArray(&interpreter->literalCache); interpreter->scope = popScope(interpreter->scope); @@ -1071,7 +1054,7 @@ static bool execFnCall(Interpreter* interpreter) { freeLiteralArray(&arguments); //call the native function - ((NativeFn) AS_FUNCTION(func) )(interpreter, &correct); + ((NativeFn) AS_FUNCTION(func).bytecode )(interpreter, &correct); freeLiteralArray(&correct); return true; @@ -1083,7 +1066,7 @@ static bool execFnCall(Interpreter* interpreter) { //init the inner interpreter manually initLiteralArray(&inner.literalCache); inner.scope = pushScope(func.as.function.scope); - inner.bytecode = AS_FUNCTION(func); + inner.bytecode = AS_FUNCTION(func).bytecode; inner.length = func.as.function.length; inner.count = 0; initLiteralArray(&inner.stack); diff --git a/source/literal.c b/source/literal.c index 5600d33..0aadff9 100644 --- a/source/literal.c +++ b/source/literal.c @@ -1,6 +1,9 @@ #include "literal.h" #include "memory.h" +#include "literal_array.h" +#include "literal_dictionary.h" + #include "console_colors.h" #include @@ -31,6 +34,16 @@ void freeLiteral(Literal literal) { return; } + if (IS_ARRAY(literal)) { + freeLiteralArray(AS_ARRAY(literal)); + return; + } + + if (IS_DICTIONARY(literal)) { + freeLiteralDictionary(AS_DICTIONARY(literal)); + return; + } + if (IS_IDENTIFIER(literal)) { FREE_ARRAY(char, AS_IDENTIFIER(literal), literal.as.identifier.length); return; @@ -40,6 +53,7 @@ void freeLiteral(Literal literal) { for (int i = 0; i < AS_TYPE(literal).count; i++) { freeLiteral(((Literal*)(AS_TYPE(literal).subtypes))[i]); } + FREE_ARRAY(Literal, AS_TYPE(literal).subtypes, AS_TYPE(literal).capacity); return; } } diff --git a/source/literal.h b/source/literal.h index f521e01..0d152c5 100644 --- a/source/literal.h +++ b/source/literal.h @@ -39,7 +39,7 @@ typedef struct { void* dictionary; struct { - void* ptr; + void* bytecode; void* scope; int length; } function; @@ -78,7 +78,7 @@ typedef struct { #define AS_STRING(value) ((value).as.string.ptr) #define AS_ARRAY(value) ((LiteralArray*)((value).as.array)) #define AS_DICTIONARY(value) ((LiteralDictionary*)((value).as.dictionary)) -#define AS_FUNCTION(value) ((value).as.function.ptr) +#define AS_FUNCTION(value) ((value).as.function) #define AS_IDENTIFIER(value) ((value).as.identifier.ptr) #define AS_TYPE(value) ((value).as.type) @@ -89,7 +89,7 @@ typedef struct { #define TO_STRING_LITERAL(value, l) _toStringLiteral(value, l) #define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = 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.bytecode = value, .function.scope = NULL, .function.length = l }}) #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 }}) diff --git a/source/literal_array.c b/source/literal_array.c index fec0f3f..daa3d3f 100644 --- a/source/literal_array.c +++ b/source/literal_array.c @@ -20,15 +20,7 @@ int pushLiteralArray(LiteralArray* array, Literal literal) { array->literals = GROW_ARRAY(Literal, array->literals, oldCapacity, array->capacity); } - //if it's a string or an identifier, make a local copy - if (IS_STRING(literal)) { - literal = TO_STRING_LITERAL(copyString(AS_STRING(literal), strlen( AS_STRING(literal) )), strlen( AS_STRING(literal) )); - } - if (IS_IDENTIFIER(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] = copyLiteral(literal); return array->count++; } @@ -75,4 +67,4 @@ void printLiteralArray(LiteralArray* array, const char* delim) { printLiteral(array->literals[i]); printf("%s", delim); } -} \ No newline at end of file +} diff --git a/source/literal_dictionary.c b/source/literal_dictionary.c index 8de5cf2..aa77377 100644 --- a/source/literal_dictionary.c +++ b/source/literal_dictionary.c @@ -8,51 +8,12 @@ //util functions static void setEntryValues(_entry* entry, Literal key, Literal value) { - //free the original string/identifier and overwrite it - if (IS_STRING(entry->key) || IS_IDENTIFIER(entry->key)) { - freeLiteral(entry->key); - } + //much simpler now + freeLiteral(entry->key); + entry->key = copyLiteral(key); - //take ownership of the copied string - if (IS_STRING(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 - else if (IS_IDENTIFIER(key)) { - entry->key = TO_IDENTIFIER_LITERAL( copyString(AS_IDENTIFIER(key), strlen( AS_IDENTIFIER(key))), strlen(AS_IDENTIFIER(key)) ); - } - - else { - freeLiteral(entry->key); //for types - entry->key = key; - } - - //values freeLiteral(entry->value); - - //take ownership of the copied string - if (IS_STRING(value)) { - char* buffer = ALLOCATE(char, strlen(AS_STRING(value)) + 1); - strncpy(buffer, AS_STRING(value), strlen(AS_STRING(value))); - buffer[strlen(AS_STRING(value))] = '\0'; - entry->value = TO_STRING_LITERAL(buffer, strlen(buffer)); - } - - //OR take ownership of the copied function - else if (IS_FUNCTION(value)) { - unsigned char* buffer = ALLOCATE(unsigned char, value.as.function.length); - memcpy(buffer, AS_FUNCTION(value), value.as.function.length); - - entry->value = TO_FUNCTION_LITERAL(buffer, value.as.function.length); - - //save the scope - entry->value.as.function.scope = value.as.function.scope; - } - - else { - entry->value = value; - } + entry->value = copyLiteral(value); } static _entry* getEntryArray(_entry* array, int capacity, Literal key, unsigned int hash, bool mustExist) { @@ -123,21 +84,6 @@ static bool setEntryArray(_entry** dictionaryHandle, int* capacityPtr, int conta _entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false); - //if it's a string or an identifier, make a local copy - if (IS_STRING(key)) { - key = TO_STRING_LITERAL(copyString(AS_STRING(key), strlen(AS_STRING(key)) ), strlen(AS_STRING(key))); - } - if (IS_IDENTIFIER(key)) { - key = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(key), strlen(AS_IDENTIFIER(key)) ), strlen(AS_IDENTIFIER(key))); - } - - if (IS_STRING(value)) { - key = TO_STRING_LITERAL(copyString(AS_STRING(value), strlen(AS_STRING(value)) ), strlen(AS_STRING(value))); - } - if (IS_IDENTIFIER(value)) { - key = TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(value), strlen(AS_IDENTIFIER(value)) ), strlen(AS_IDENTIFIER(value))); - } - //true = contains increase if (IS_NULL(entry->key)) { setEntryValues(entry, key, value); @@ -237,4 +183,4 @@ bool existsLiteralDictionary(LiteralDictionary* dictionary, Literal key) { //null & not tombstoned _entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), false); return !(IS_NULL(entry->key) && IS_NULL(entry->value)); -} \ No newline at end of file +} diff --git a/source/literal_util.c b/source/literal_util.c index 82c4175..2e7083e 100644 --- a/source/literal_util.c +++ b/source/literal_util.c @@ -2,12 +2,86 @@ #include "literal_array.h" #include "literal_dictionary.h" +#include "scope.h" #include "memory.h" #include "console_colors.h" #include +Literal copyLiteral(Literal original) { + switch(original.type) { + case LITERAL_NULL: + case LITERAL_BOOLEAN: + case LITERAL_INTEGER: + case LITERAL_FLOAT: + //no copying needed + return original; + + case LITERAL_STRING: { + return TO_STRING_LITERAL(copyString(AS_STRING(original), strlen(AS_STRING(original)) ), strlen(AS_STRING(original))); + } + + case LITERAL_ARRAY: { + LiteralArray* array = ALLOCATE(LiteralArray, 1); + initLiteralArray(array); + + //copy each element + for (int i = 0; i < AS_ARRAY(original)->count; i++) { + pushLiteralArray(array, copyLiteral(AS_ARRAY(original)->literals[i])); + } + + return TO_ARRAY_LITERAL(array); + } + + case LITERAL_DICTIONARY: { + LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1); + initLiteralDictionary(dictionary); + + //copy each entry + for (int i = 0; i < AS_DICTIONARY(original)->capacity; i++) { + if ( !IS_NULL(AS_DICTIONARY(original)->entries[i].key) ) { + setLiteralDictionary(dictionary, copyLiteral(AS_DICTIONARY(original)->entries[i].key), copyLiteral(AS_DICTIONARY(original)->entries[i].value)); + } + } + + return TO_DICTIONARY_LITERAL(dictionary); + } + + case LITERAL_FUNCTION: { + unsigned char* buffer = ALLOCATE(unsigned char, AS_FUNCTION(original).length); + memcpy(buffer, AS_FUNCTION(original).bytecode, AS_FUNCTION(original).length); + + Literal literal = TO_FUNCTION_LITERAL(buffer, AS_FUNCTION(original).length); + AS_FUNCTION(literal).scope = copyScope(AS_FUNCTION(original).scope); + + return literal; + } + + case LITERAL_IDENTIFIER: { + return TO_IDENTIFIER_LITERAL(copyString(AS_IDENTIFIER(original), strlen(AS_IDENTIFIER(original)) ), strlen(AS_IDENTIFIER(original))); + } + + case LITERAL_TYPE: { + Literal lit = TO_TYPE_LITERAL(AS_TYPE(original).typeOf, AS_TYPE(original).constant); + + for (int i = 0; i < AS_TYPE(original).count; i++) { + TYPE_PUSH_SUBTYPE(&lit, copyLiteral( ((Literal*)(AS_TYPE(original).subtypes))[i] )); + } + + return lit; + } + + case LITERAL_FUNCTION_NATIVE: + //no copying possible + return original; + + default: + fprintf(stderr, ERROR "ERROR: Can't copy that literal type: %d\n" RESET, original.type); + return TO_NULL_LITERAL; + } +} + char* copyString(char* original, int length) { //make a local copy of the char array char* buffer = ALLOCATE(char, length + 1); @@ -495,4 +569,4 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { //should never be seen fprintf(stderr, ERROR "[internal] Unrecognized literal type in print: %d\n" RESET, literal.type); } -} \ No newline at end of file +} diff --git a/source/literal_util.h b/source/literal_util.h index 520c2e0..fceebbf 100644 --- a/source/literal_util.h +++ b/source/literal_util.h @@ -2,6 +2,7 @@ #include "literal.h" +Literal copyLiteral(Literal original); char* copyString(char* original, int length); bool literalsAreEqual(Literal lhs, Literal rhs); int hashLiteral(Literal lit); @@ -9,4 +10,3 @@ int hashLiteral(Literal lit); void printLiteral(Literal literal); void printLiteralCustom(Literal literal, void (printFn)(const char*)); -//TODO: copy literal (to be used in dictionaries and arrays, as well) diff --git a/source/memory.c b/source/memory.c index 603b43c..9e9acb2 100644 --- a/source/memory.c +++ b/source/memory.c @@ -5,12 +5,7 @@ #include #include -static int allocatedMemoryCount = 0; - void* reallocate(void* pointer, size_t oldSize, size_t newSize) { - allocatedMemoryCount -= oldSize; - allocatedMemoryCount += newSize; - if (newSize == 0) { free(pointer); @@ -27,6 +22,3 @@ void* reallocate(void* pointer, size_t oldSize, size_t newSize) { return mem; } -int getAllocatedMemoryCount() { - return allocatedMemoryCount; -} \ No newline at end of file diff --git a/source/memory.h b/source/memory.h index 9f6b150..c988867 100644 --- a/source/memory.h +++ b/source/memory.h @@ -12,4 +12,3 @@ void* reallocate(void* pointer, size_t oldSize, size_t newSize); -int getAllocatedMemoryCount(); \ No newline at end of file diff --git a/source/repl_main.c b/source/repl_main.c index b1b7958..e2918fa 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -153,10 +153,6 @@ void repl() { initInterpreter(&interpreter); for(;;) { - if (command.verbose) { - //print the used memory footprint - printf("%d ", getAllocatedMemoryCount()); - } printf("> "); fgets(input, size, stdin); diff --git a/source/scope.c b/source/scope.c index 856d7ef..9fc5638 100644 --- a/source/scope.c +++ b/source/scope.c @@ -128,6 +128,30 @@ Scope* popScope(Scope* scope) { return ret; } +Scope* copyScope(Scope* original) { + Scope* scope = ALLOCATE(Scope, 1); + scope->ancestor = original->ancestor; + initLiteralDictionary(&scope->variables); + initLiteralDictionary(&scope->types); + + //tick up all scope reference counts + scope->references = 0; + for (Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) { + ptr->references++; + } + + //copy the contents of the dictionaries + for (int i = 0; i < original->variables.capacity; i++) { + setLiteralDictionary(&scope->variables, original->variables.entries[i].key, original->variables.entries[i].value); + } + + for (int i = 0; i < original->variables.capacity; i++) { + setLiteralDictionary(&scope->types, original->types.entries[i].key, original->types.entries[i].value); + } + + return scope; +} + //returns false if error bool declareScopeVariable(Scope* scope, Literal key, Literal type) { //don't redefine a variable within this scope diff --git a/source/scope.h b/source/scope.h index 91af0db..153d837 100644 --- a/source/scope.h +++ b/source/scope.h @@ -12,6 +12,7 @@ typedef struct Scope { Scope* pushScope(Scope* scope); Scope* popScope(Scope* scope); +Scope* copyScope(Scope* original); //returns false if error bool declareScopeVariable(Scope* scope, Literal key, Literal type); @@ -21,4 +22,4 @@ bool isDelcaredScopeVariable(Scope* scope, Literal key); bool setScopeVariable(Scope* scope, Literal key, Literal value, bool constCheck); bool getScopeVariable(Scope* scope, Literal key, Literal* value); -Literal getScopeType(Scope* scope, Literal key); \ No newline at end of file +Literal getScopeType(Scope* scope, Literal key); diff --git a/test/makefile b/test/makefile index 97d076d..359b517 100644 --- a/test/makefile +++ b/test/makefile @@ -9,11 +9,17 @@ TARGETS = $(filter-out $(wildcard ../source/*main.c),$(wildcard ../source/*.c)) TESTS = $(wildcard *.c) OBJ = $(addprefix $(ODIR)/,$(TARGETS:../source/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o)) +.PRECIOUS: $(TESTS:%.c=../$(OUTDIR)/%.exe) + all: $(OBJ) $(TESTS:%.c=../$(OUTDIR)/%.exe) ../$(OUTDIR)/%.exe: $(ODIR)/%.o @$(CC) -o $@ $< $(TARGETS:../source/%.c=$(ODIR)/%.o) $(CFLAGS) $(LIBS) - $@ +ifeq ($(shell uname),Linux) + valgrind $@ +else + @echo please run these tests with valgrind on linux +endif $(OBJ): | $(ODIR) @@ -29,4 +35,4 @@ $(ODIR)/%.o: ../source/%.c .PHONY: clean clean: - $(RM) $(ODIR) \ No newline at end of file + $(RM) $(ODIR) diff --git a/test/test_literal.c b/test/test_literal.c index 6eccd2d..1c3e0b5 100644 --- a/test/test_literal.c +++ b/test/test_literal.c @@ -49,12 +49,6 @@ int main() { 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; -} \ No newline at end of file +} diff --git a/test/test_literal_array.c b/test/test_literal_array.c index c375911..3b5ff97 100644 --- a/test/test_literal_array.c +++ b/test/test_literal_array.c @@ -67,12 +67,6 @@ int main() { freeLiteralArray(&array); } - //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; -} \ No newline at end of file +} diff --git a/test/test_memory.c b/test/test_memory.c index c956fbd..9c23174 100644 --- a/test/test_memory.c +++ b/test/test_memory.c @@ -10,11 +10,6 @@ int main() { int* integer = ALLOCATE(int, 1); FREE(int, integer); - - if (getAllocatedMemoryCount() != 0) { - fprintf(stderr, ERROR "ERROR: integer failed to be allocated and freed correctly\n" RESET); - return -1; - } } { @@ -22,11 +17,6 @@ int main() { int* array = ALLOCATE(int, 10); FREE_ARRAY(int, array, 10); - - if (getAllocatedMemoryCount() != 0) { - fprintf(stderr, ERROR "ERROR: integer array failed to be allocated and freed correctly\n" RESET); - return -1; - } } { @@ -36,11 +26,6 @@ int main() { FREE_ARRAY(int, array1, 10); FREE_ARRAY(int, array2, 10); - - if (getAllocatedMemoryCount() != 0) { - fprintf(stderr, ERROR "ERROR: integer array failed to be allocated and freed correctly\n" RESET); - return -1; - } } printf(NOTICE "All good\n" RESET);