From e6ad46f1ff627c82ba47a569bbe316134bedcc0a Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 13 Aug 2024 23:42:14 +1000 Subject: [PATCH] Wrote value, chunk, memory sections, tested value chunk and memory remain untested for now --- makefile | 10 ++++---- source/toy_chunk.c | 24 ++++++++++++++++++ source/toy_chunk.h | 13 ++++++++++ source/toy_lexer.c | 4 +-- source/toy_memory.c | 22 ++++++++++++++++ source/toy_memory.h | 14 ++++++++++ source/toy_opcodes.h | 5 ++++ source/toy_value.c | 21 +++++++++++++++ source/toy_value.h | 55 ++++++++++++++++++++++++++++++++++++++++ tests/cases/test_value.c | 39 ++++++++++++++++++++++++++++ tests/makefile | 7 ++--- 11 files changed, 204 insertions(+), 10 deletions(-) create mode 100644 source/toy_chunk.c create mode 100644 source/toy_chunk.h create mode 100644 source/toy_memory.c create mode 100644 source/toy_memory.h create mode 100644 source/toy_opcodes.h create mode 100644 source/toy_value.c create mode 100644 source/toy_value.h create mode 100644 tests/cases/test_value.c diff --git a/makefile b/makefile index ec75c25..8719eb0 100644 --- a/makefile +++ b/makefile @@ -1,14 +1,14 @@ +#compiler settings +CFLAGS+=-std=c17 -pedantic -Werror +LIBS=-lm + #directories export TOY_SOURCEDIR=source export TOY_OUTDIR=out export TOY_OBJDIR=obj -#compiler settings -CFLAGS+=-std=c17 -pedantic -Werror -LIBS=-lm - #file names -TOY_SOURCEFILES=$(wildcard $(TOY_SOURCEDIR)/*.c) +export TOY_SOURCEFILES=$(wildcard $(TOY_SOURCEDIR)/*.c) #targets all: clean tests diff --git a/source/toy_chunk.c b/source/toy_chunk.c new file mode 100644 index 0000000..288b559 --- /dev/null +++ b/source/toy_chunk.c @@ -0,0 +1,24 @@ +#include "toy_chunk.h" + +#include "toy_memory.h" + +void Toy_initChunk(Toy_Chunk* chunk) { + chunk->count = 0; + chunk->capacity = 0; + chunk->code = NULL; +} + +void Toy_pushChunk(Toy_Chunk* chunk, uint8_t byte) { + if (chunk->count +1 > chunk->capacity) { + int oldCapacity = chunk->capacity; + chunk->capacity = TOY_GROW_CAPACITY(oldCapacity); + chunk->code = TOY_GROW_ARRAY(uint8_t, chunk->code, oldCapacity, chunk->capacity); + } + + chunk->code[chunk->count++] = byte; +} + +void Toy_freeChunk(Toy_Chunk* chunk) { + TOY_FREE_ARRAY(uint8_t, chunk->code, chunk->capacity); + Toy_initChunk(chunk); +} diff --git a/source/toy_chunk.h b/source/toy_chunk.h new file mode 100644 index 0000000..ace9190 --- /dev/null +++ b/source/toy_chunk.h @@ -0,0 +1,13 @@ +#pragma once + +#include "toy_common.h" + +typedef struct Toy_Chunk { + int count; + int capacity; + uint8_t* code; +} Toy_Chunk; + +TOY_API void Toy_initChunk(Toy_Chunk* chunk); +TOY_API void Toy_pushChunk(Toy_Chunk* chunk, uint8_t byte); +TOY_API void Toy_freeChunk(Toy_Chunk* chunk); diff --git a/source/toy_lexer.c b/source/toy_lexer.c index 4349926..5102095 100644 --- a/source/toy_lexer.c +++ b/source/toy_lexer.c @@ -317,13 +317,13 @@ static void trim(char** s, int* l) { //util void Toy_private_printToken(Toy_Token* token) { //print errors if (token->type == TOY_TOKEN_ERROR) { - printf(TOY_CC_ERROR "Error\t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme); + printf(TOY_CC_ERROR "ERROR: \t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme); return; } //read pass token, even though it isn't generated if (token->type == TOY_TOKEN_PASS) { - printf(TOY_CC_NOTICE "Error\t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme); + printf(TOY_CC_NOTICE "PASS: \t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme); return; } diff --git a/source/toy_memory.c b/source/toy_memory.c new file mode 100644 index 0000000..ef1b2ff --- /dev/null +++ b/source/toy_memory.c @@ -0,0 +1,22 @@ +#include "toy_memory.h" + +#include "toy_console_colors.h" + +#include +#include + +void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) { + if (newSize == 0) { + free(pointer); + return NULL; + } + + void* result = realloc(pointer, newSize); + + if (result == NULL) { + fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize); + exit(1); + } + + return result; +} \ No newline at end of file diff --git a/source/toy_memory.h b/source/toy_memory.h new file mode 100644 index 0000000..b3649bf --- /dev/null +++ b/source/toy_memory.h @@ -0,0 +1,14 @@ +#pragma once + +#include "toy_common.h" + +#define TOY_GROW_CAPACITY(capacity) \ + ((capacity) < 8 ? 8 : (capacity) * 2) + +#define TOY_GROW_ARRAY(type, pointer, oldSize, newSize) \ + (type*)Toy_reallocate(pointer, sizeof(type)*oldSize, sizeof(type)*newSize) + +#define TOY_FREE_ARRAY(type, pointer, oldSize) \ + (type*)Toy_reallocate(pointer, sizeof(type)*oldSize, 0) + +TOY_API void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize); diff --git a/source/toy_opcodes.h b/source/toy_opcodes.h new file mode 100644 index 0000000..ce19e20 --- /dev/null +++ b/source/toy_opcodes.h @@ -0,0 +1,5 @@ +#pragma once + +typedef enum Toy_OpcodeType { + TOY_OPCODE_RETURN, +} Toy_OpcodeType; diff --git a/source/toy_value.c b/source/toy_value.c new file mode 100644 index 0000000..e6e1791 --- /dev/null +++ b/source/toy_value.c @@ -0,0 +1,21 @@ +#include "toy_value.h" + +#include "toy_console_colors.h" + +#include + +bool Toy_private_isTruthy(Toy_Value value) { + //null is an error + if (TOY_VALUE_IS_NULL(value)) { + fprintf(stderr, TOY_CC_ERROR "ERROR: 'null' is neither true nor false\n" TOY_CC_RESET); + return false; + } + + //only 'false' is falsy + if (TOY_VALUE_IS_BOOLEAN(value)) { + return TOY_VALUE_AS_BOOLEAN(value); + } + + //anything else is truthy + return true; +} \ No newline at end of file diff --git a/source/toy_value.h b/source/toy_value.h new file mode 100644 index 0000000..04d711a --- /dev/null +++ b/source/toy_value.h @@ -0,0 +1,55 @@ +#pragma once + +#include "toy_common.h" + +typedef enum Toy_ValueType { + TOY_VALUE_NULL, + TOY_VALUE_BOOLEAN, + TOY_VALUE_INTEGER, + TOY_VALUE_FLOAT, + TOY_VALUE_STRING, + TOY_VALUE_ARRAY, + TOY_VALUE_DICTIONARY, + TOY_VALUE_FUNCTION, + TOY_VALUE_OPAQUE, +} Toy_ValueType; + +typedef struct Toy_Value { + union { + bool boolean; //1 + int integer; //4 + float number; //4 + //TODO: strings + //TODO: arrays + //TODO: dictonaries + //TODO: functions + //TODO: opaque + } as; //4 + + Toy_ValueType type; //4 bytes +} Toy_Value; + +#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL) +#define TOY_VALUE_IS_BOOLEAN(value) ((value).type == TOY_VALUE_BOOLEAN) +#define TOY_VALUE_IS_INTEGER(value) ((value).type == TOY_VALUE_INTEGER) +#define TOY_VALUE_IS_FLOAT(value) ((value).type == TOY_VALUE_FLOAT) +#define TOY_VALUE_IS_STRING(value) ((value).type == TOY_VALUE_STRING) +#define TOY_VALUE_IS_ARRAY(value) ((value).type == TOY_VALUE_ARRAY) +#define TOY_VALUE_IS_DICTIONARY(value) ((value).type == TOY_VALUE_DICTIONARY) +#define TOY_VALUE_IS_FUNCTION(value) ((value).type == TOY_VALUE_FUNCTION) +#define TOY_VALUE_IS_OPAQUE(value) ((value).type == TOY_VALUE_OPAQUE) + +#define TOY_VALUE_AS_BOOLEAN(value) ((value).as.boolean) +#define TOY_VALUE_AS_INTEGER(value) ((value).as.integer) +#define TOY_VALUE_AS_FLOAT(value) ((value).as.number) +//TODO: more + +#define TOY_VALUE_TO_NULL() ((Toy_Value){{ .integer = 0 }, TOY_VALUE_NULL}) +#define TOY_VALUE_TO_BOOLEAN(value) ((Toy_Value){{ .boolean = value }, TOY_VALUE_BOOLEAN}) +#define TOY_VALUE_TO_INTEGER(value) ((Toy_Value){{ .integer = value }, TOY_VALUE_INTEGER}) +#define TOY_VALUE_TO_FLOAT(value) ((Toy_Value){{ .number = value }, TOY_VALUE_FLOAT}) +//TODO: more + +#define TOY_VALUE_IS_TRUTHY(value) Toy_private_isTruthy(value) +TOY_API bool Toy_private_isTruthy(Toy_Value value); + diff --git a/tests/cases/test_value.c b/tests/cases/test_value.c new file mode 100644 index 0000000..a48d389 --- /dev/null +++ b/tests/cases/test_value.c @@ -0,0 +1,39 @@ +#include "toy_value.h" +#include "toy_console_colors.h" + +#include +#include + +int main() { + //test for the correct size + { + if (sizeof(Toy_Value) != 8) { + fprintf(stderr, TOY_CC_ERROR "ERROR: 'Toy_Value' is an unexpected size in memory\n" TOY_CC_RESET); + return -1; + } + } + + //test creating a null + { + Toy_Value v = TOY_VALUE_TO_NULL(); + + if (!TOY_VALUE_IS_NULL(v)) { + fprintf(stderr, TOY_CC_ERROR "ERROR: creating a 'null' value failed\n" TOY_CC_RESET); + return -1; + } + } + + //test creating values + { + Toy_Value t = TOY_VALUE_TO_BOOLEAN(true); + Toy_Value f = TOY_VALUE_TO_BOOLEAN(false); + + if (!TOY_VALUE_IS_TRUTHY(t) || TOY_VALUE_IS_TRUTHY(f)) { + fprintf(stderr, TOY_CC_ERROR "ERROR: 'boolean' value failed\n" TOY_CC_RESET); + return -1; + } + } + + printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); + return 0; +} diff --git a/tests/makefile b/tests/makefile index d9b8f5c..f0fe789 100644 --- a/tests/makefile +++ b/tests/makefile @@ -3,14 +3,15 @@ CFLAGS=-g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-v LIBS=-lm #directories -TEST_SOURCEDIR=../$(TOY_SOURCEDIR) +TEST_ROOTDIR=.. +TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR) TEST_CASESDIR=cases TEST_OUTDIR=out TEST_OBJDIR=obj #file names -TEST_SOURCEFILES=$(wildcard $(TEST_SOURCEDIR)/*.c) +TEST_SOURCEFILES=$(addprefix $(TOY_ROOTDIR)/,$(TOY_SOURCEFILES)) TEST_CASESFILES=$(wildcard $(TEST_CASESDIR)/*.c) #build the object files, compile the test cases, and run @@ -39,7 +40,7 @@ $(TEST_OBJDIR)/%.o: $(TEST_CASESDIR)/%.c #final linking step (with extra flags to strip dead code) $(TEST_OUTDIR)/%.exe: $(TEST_OBJDIR)/%.o - @$(CC) -o $@ $(shell find $(TEST_OBJDIR) -name '*.o') $(CFLAGS) $(LIBS) -Wl,--gc-sections + @$(CC) -o $@ $< $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o))) $(CFLAGS) $(LIBS) -Wl,--gc-sections $@ #util commands