diff --git a/.github/workflows/continuous-integration-v2.yml b/.github/workflows/continuous-integration-v2.yml index fa4bb41..957589d 100644 --- a/.github/workflows/continuous-integration-v2.yml +++ b/.github/workflows/continuous-integration-v2.yml @@ -14,21 +14,24 @@ on: - dev workflow_dispatch: -#testing the CI workflows while nothing is functional yet +#CI workflows using a matrix jobs: - test-ubuntu-latest: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: make tests (ubuntu) - run: make tests - - test-windows-latest: - runs-on: windows-latest + run-test-suites: + strategy: + matrix: + platforms: + - { os: ubuntu-latest, preinstall: sudo apt-get install gdb, gdb_skip: false } + - { os: windows-latest, preinstall: , gdb_skip: false } + - { os: macos-latest, preinstall: , gdb_skip: true } + commands: + - make tests + - make tests-gdb + runs-on: ${{ matrix.platforms.os }} steps: - uses: actions/checkout@v4 - - name: make tests (windows) - run: make tests - + - name: Preinstall dependencies + run: ${{ matrix.platforms.preinstall }} + - name: run the test suites + if: matrix.platforms.gdb_skip != true + run: ${{ matrix.commands }} diff --git a/makefile b/makefile index 5afdc74..4305bf4 100644 --- a/makefile +++ b/makefile @@ -19,6 +19,10 @@ all: clean tests tests: $(MAKE) -C tests -k +.PHONY: tests-gdb +tests-gdb: + $(MAKE) -C tests all-gdb -k + #util targets $(TOY_OUTDIR): mkdir $(TOY_OUTDIR) diff --git a/source/toy_ast.h b/source/toy_ast.h index 6a7fd4e..e87253f 100644 --- a/source/toy_ast.h +++ b/source/toy_ast.h @@ -110,14 +110,14 @@ typedef struct Toy_AstEnd { Toy_AstType type; } Toy_AstEnd; -union Toy_Ast { - Toy_AstType type; //4 - Toy_AstBlock block; //12 - Toy_AstValue value; //12 - Toy_AstUnary unary; //12 - Toy_AstBinary binary; //16 - Toy_AstGroup group; //8 - Toy_AstPass pass; //4 - Toy_AstError error; //4 - Toy_AstEnd end; //4 -}; //16 +union Toy_Ast { //32 | 64 BITNESS + Toy_AstType type; //4 | 4 + Toy_AstBlock block; //16 | 32 + Toy_AstValue value; //12 | 12 + Toy_AstUnary unary; //12 | 16 + Toy_AstBinary binary; //16 | 24 + Toy_AstGroup group; //8 | 16 + Toy_AstPass pass; //4 | 4 + Toy_AstError error; //4 | 4 + Toy_AstEnd end; //4 | 4 +}; //16 | 32 diff --git a/source/toy_common.h b/source/toy_common.h index d31dc10..642b3fd 100644 --- a/source/toy_common.h +++ b/source/toy_common.h @@ -6,29 +6,38 @@ #include //TOY_API is platform-dependant, and marks publicly usable API functions -#if defined(__GNUC__) +#if defined(__linux__) #define TOY_API extern -#elif defined(_MSC_VER) - #ifndef TOY_EXPORT +#elif defined(_WIN32) || defined(_WIN64) + #if defined(TOY_EXPORT) + #define TOY_API __declspec(dllexport) + #elif defined(TOY_IMPORT) #define TOY_API __declspec(dllimport) #else - #define TOY_API __declspec(dllexport) + #define TOY_API extern #endif +#elif defined(__APPLE__) + #define TOY_API extern #else //generic solution #define TOY_API extern #endif //TOY_BITNESS is used to encourage memory-cache friendliness -//source: https://www.linuxquestions.org/questions/programming-9/c-preprocessor-define-for-32-vs-64-bit-long-int-4175658579/ -#if defined(__GNUC__) - #if defined(__x86_64) +#if defined(__linux__) + #if defined(__LP64__) #define TOY_BITNESS 64 #else #define TOY_BITNESS 32 #endif -#elif defined(_MSC_VER) - #if defined(_M_X64) +#elif defined(_WIN32) || defined(_WIN64) + #if defined(_WIN64) + #define TOY_BITNESS 64 + #else + #define TOY_BITNESS 32 + #endif +#elif defined(__APPLE__) + #if defined(__LP64__) #define TOY_BITNESS 64 #else #define TOY_BITNESS 32 diff --git a/source/toy_keywords.c b/source/toy_keywords.c index dec78a4..b105882 100644 --- a/source/toy_keywords.c +++ b/source/toy_keywords.c @@ -41,6 +41,7 @@ const Toy_KeywordTypeTuple Toy_private_keywords[] = { {TOY_TOKEN_KEYWORD_TYPEOF, "typeof"}, {TOY_TOKEN_KEYWORD_VAR, "var"}, {TOY_TOKEN_KEYWORD_WHILE, "while"}, + {TOY_TOKEN_KEYWORD_YIELD, "yield"}, //literal values {TOY_TOKEN_LITERAL_TRUE, "true"}, diff --git a/source/toy_opcodes.h b/source/toy_opcodes.h index 23e5767..176964d 100644 --- a/source/toy_opcodes.h +++ b/source/toy_opcodes.h @@ -36,5 +36,5 @@ typedef enum Toy_OpcodeType { //meta instructions TOY_OPCODE_PASS, TOY_OPCODE_ERROR, - TOY_OPCODE_EOF, + TOY_OPCODE_EOF = 255, } Toy_OpcodeType; diff --git a/source/toy_parser.c b/source/toy_parser.c index 070f069..d4efab5 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -154,6 +154,7 @@ static ParsingTuple parsingRulesetTable[] = { {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_TYPEOF, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_VAR, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_WHILE, + {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_YIELD, //literal values {PREC_PRIMARY,atomic,NULL},// TOY_TOKEN_LITERAL_TRUE, diff --git a/source/toy_routine.c b/source/toy_routine.c index ce5d9de..3ff9b07 100644 --- a/source/toy_routine.c +++ b/source/toy_routine.c @@ -281,12 +281,12 @@ static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) { expand(&buffer, &capacity, &count, rt->codeCount); memcpy((buffer + count), rt->code, rt->codeCount); - ((int*)buffer)[codeAddr] = count; + *((int*)(buffer + codeAddr)) = count; count += rt->codeCount; } //finally, record the total size, and return the result - ((int*)buffer)[0] = count; + *((int*)buffer) = count; return buffer; } diff --git a/source/toy_token_types.h b/source/toy_token_types.h index f60eaba..849026f 100644 --- a/source/toy_token_types.h +++ b/source/toy_token_types.h @@ -43,6 +43,7 @@ typedef enum Toy_TokenType { TOY_TOKEN_KEYWORD_TYPEOF, TOY_TOKEN_KEYWORD_VAR, TOY_TOKEN_KEYWORD_WHILE, + TOY_TOKEN_KEYWORD_YIELD, //literal values TOY_TOKEN_LITERAL_TRUE, diff --git a/tests/cases/test_ast.c b/tests/cases/test_ast.c index be56386..9e15393 100644 --- a/tests/cases/test_ast.c +++ b/tests/cases/test_ast.c @@ -3,6 +3,33 @@ #include +int test_sizeof_ast_64bit() { +#define TEST_SIZEOF(type, size) \ + if (sizeof(type) != size) { \ + fprintf(stderr, TOY_CC_ERROR "ERROR: sizeof(" #type ") is %d, expected %d\n" TOY_CC_RESET, (int)sizeof(type), size); \ + ++err; \ + } + + //count errors + int err = 0; + + //run for each type + TEST_SIZEOF(Toy_AstType, 4); + TEST_SIZEOF(Toy_AstBlock, 32); + TEST_SIZEOF(Toy_AstValue, 12); + TEST_SIZEOF(Toy_AstUnary, 16); + TEST_SIZEOF(Toy_AstBinary, 24); + TEST_SIZEOF(Toy_AstGroup, 16); + TEST_SIZEOF(Toy_AstPass, 4); + TEST_SIZEOF(Toy_AstError, 4); + TEST_SIZEOF(Toy_AstEnd, 4); + TEST_SIZEOF(Toy_Ast, 32); + +#undef TEST_SIZEOF + + return -err; +} + int test_sizeof_ast_32bit() { #define TEST_SIZEOF(type, size) \ if (sizeof(type) != size) { \ @@ -22,6 +49,7 @@ int test_sizeof_ast_32bit() { TEST_SIZEOF(Toy_AstGroup, 8); TEST_SIZEOF(Toy_AstPass, 4); TEST_SIZEOF(Toy_AstError, 4); + TEST_SIZEOF(Toy_AstEnd, 4); TEST_SIZEOF(Toy_Ast, 16); #undef TEST_SIZEOF @@ -168,7 +196,15 @@ int main() { //run each test set, returning the total errors given int total = 0, res = 0; -#if TOY_BITNESS == 32 + +#if TOY_BITNESS == 64 + res = test_sizeof_ast_64bit(); + total += res; + + if (res == 0) { + printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); + } +#elif TOY_BITNESS == 32 res = test_sizeof_ast_32bit(); total += res; @@ -176,7 +212,7 @@ int main() { printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); } #else - fprintf(stderr, TOY_CC_WARN "WARNING: Skipping test_sizeof_ast_32bit(); Can't determine the 'bitness' of this platform\n" TOY_CC_RESET); + fprintf(stderr, TOY_CC_WARN "WARNING: Skipping test_sizeof_ast_*bit(); Can't determine the 'bitness' of this platform (seems to be %d)\n" TOY_CC_RESET, TOY_BITNESS); #endif { diff --git a/tests/makefile b/tests/makefile index 6a61a57..87869f1 100644 --- a/tests/makefile +++ b/tests/makefile @@ -3,6 +3,16 @@ CC=gcc CFLAGS=-g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable LIBS=-lm +ifeq ($(shell uname),Linux) +LDFLAG=-Wl,--gc-sections +else ifeq ($(OS),Windows_NT) +LDFLAG=-Wl,--gc-sections +else ifeq ($(shell uname),Darwin) +LDFLAG=-Wl,-dead_strip +else + @echo "LDFLAG set failed - what platform is this?" +endif + #directories TEST_ROOTDIR=.. TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR) @@ -16,14 +26,20 @@ TEST_SOURCEFILES=$(addprefix $(TOY_ROOTDIR)/,$(TOY_SOURCEFILES)) TEST_CASESFILES=$(wildcard $(TEST_CASESDIR)/*.c) #build the object files, compile the test cases, and run -all: clean build-source build-cases $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) +all: clean build-source build-cases build-link build-run -#targets for each set of source files +#targets for each step .PHONY: build-source build-source: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o))) .PHONY: build-cases -build-cases: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_CASESFILES:.c=.o))) +build-cases: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_CASESFILES:.c=.o))) + +.PHONY: build-link +build-link: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) + +.PHONY: build-run +build-run: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run))) #util targets $(TEST_OUTDIR): @@ -32,17 +48,29 @@ $(TEST_OUTDIR): $(TEST_OBJDIR): mkdir $(TEST_OBJDIR) -#compilation step +#compilation steps $(TEST_OBJDIR)/%.o: $(TEST_SOURCEDIR)/%.c $(CC) -c -o $@ $< $(addprefix -I,$(TEST_SOURCEDIR)) $(CFLAGS) -fdata-sections -ffunction-sections $(TEST_OBJDIR)/%.o: $(TEST_CASESDIR)/%.c $(CC) -c -o $@ $< $(addprefix -I,$(TEST_SOURCEDIR) $(TEST_CASESDIR)) $(CFLAGS) -fdata-sections -ffunction-sections -#final linking step (with extra flags to strip dead code) $(TEST_OUTDIR)/%.exe: $(TEST_OBJDIR)/%.o - @$(CC) -o $@ $< $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o))) $(CFLAGS) $(LIBS) -Wl,--gc-sections - $@ + @$(CC) -o $@ $< $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o))) $(CFLAGS) $(LIBS) $(LDFLAGS) + +.PRECIOUS: $(TEST_OUTDIR)/%.run +$(TEST_OUTDIR)/%.run: $(TEST_OUTDIR)/%.exe + $< + +#debugging targets +all-gdb: clean build-source build-cases build-link build-run-gdb + +.PHONY: build-run-gdb +build-run-gdb: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run-gdb))) + +.PRECIOUS: $(TEST_OUTDIR)/%.run-gdb +$(TEST_OUTDIR)/%.run-gdb: $(TEST_OUTDIR)/%.exe + gdb $< -ex "run" --batch #util commands .PHONY: clean