Lexer tests working

This commit is contained in:
Kyler Olsen 2025-11-04 23:16:00 -07:00
parent 2ea933c8b1
commit 906a632fef
9 changed files with 220 additions and 146 deletions

View File

@ -3,6 +3,7 @@
CC ?= gcc CC ?= gcc
CFLAGS ?= -std=c11 -Wall -Wextra -g -Iinclude -MMD -MP CFLAGS ?= -std=c11 -Wall -Wextra -g -Iinclude -MMD -MP
LDFLAGS ?= LDFLAGS ?=
CTESTFLAGS ?= -std=c11 -Wall -Wextra -Wno-unused-function -g -Iinclude -MMD -MP
SRCDIR := src SRCDIR := src
OBJDIR := obj OBJDIR := obj
@ -34,11 +35,11 @@ $(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)/%.o: $(TESTDIR)/%.c | $(OBJDIR) $(OBJDIR)/%.o: $(TESTDIR)/%.c | $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CTESTFLAGS) -c $< -o $@
# Link main program # Link main program
$(TARGET): $(OBJECTS) | $(BINDIR) $(TARGET): $(OBJECTS) | $(BINDIR)
$(CC) $(LDFLAGS) $^ -o $@ $(CC) $(LDFLAGS) $^ -o $@ -lm
# Run main program # Run main program
run: $(TARGET) run: $(TARGET)
@ -47,7 +48,7 @@ run: $(TARGET)
# Build test runner executable # Build test runner executable
$(TEST_TARGET): $(TEST_OBJECTS) $(OBJECTS) | $(BINDIR) $(TEST_TARGET): $(TEST_OBJECTS) $(OBJECTS) | $(BINDIR)
$(CC) $(LDFLAGS) $^ -o $@ $(CC) $(LDFLAGS) $^ -o $@ -lm
# Run tests # Run tests
test: $(TEST_TARGET) test: $(TEST_TARGET)

View File

@ -6,11 +6,11 @@
#ifndef SLS_LEXER_H #ifndef SLS_LEXER_H
#define SLS_LEXER_H #define SLS_LEXER_H
#include <stdint.h> #include <stddef.h>
#include "sls_errors.h" #include "sls_errors.h"
const size_t TYPE_NAMES_SAFE_LENGTH = 20; extern const size_t TYPE_NAMES_SAFE_LENGTH;
typedef struct { typedef struct {
const char *filename; const char *filename;
@ -33,18 +33,7 @@ typedef enum {
TOKEN_TYPE_TUPLE, TOKEN_TYPE_TUPLE,
} TokenType; } TokenType;
const char *TOKEN_TYPES_NAMES[] = { extern const char *TOKEN_TYPES_NAMES[];
"End of File",
"Identifier",
"Integer",
"Float",
"Double",
"String",
"Boolean",
"Array",
"Token String",
"Type Tuple",
};
typedef enum { typedef enum {
ARRAY_IDENTIFIER, ARRAY_IDENTIFIER,
@ -63,22 +52,7 @@ typedef enum {
ARRAY_STRUCT_INLINE, ARRAY_STRUCT_INLINE,
} ArrayType; } ArrayType;
const char *ARRAY_TYPES_NAMES[] = { extern const char *ARRAY_TYPES_NAMES[];
"Identifier",
"i64",
"i32",
"i16",
"i8",
"u64",
"u32",
"u16",
"u8",
"Float",
"Double",
"String",
"Boolean",
"Inline Struct",
};
typedef struct { typedef struct {
const char *name; const char *name;
@ -97,16 +71,7 @@ typedef enum {
INTEGER_U8, INTEGER_U8,
} IntegerBuiltInType; } IntegerBuiltInType;
const char *INTEGER_TYPES_NAMES[] = { extern const char *INTEGER_TYPES_NAMES[];
"i64",
"i32",
"i16",
"i8",
"u64",
"u32",
"u16",
"u8",
};
typedef struct { typedef struct {
uint64_t value; uint64_t value;
@ -188,8 +153,8 @@ typedef struct {
} LexerResult; } LexerResult;
void init_lexer(LexerInfo *lexer_info, const char *filename, const char *source_code); void init_lexer(LexerInfo *lexer_info, const char *filename, const char *source_code);
LexerResult lexical_analysis(LexerInfo *lexer_info);
LexerTokenResult *get_token(LexerTokenResult *head, size_t i); LexerTokenResult *get_token(LexerTokenResult *head, size_t i);
void clean_token_result(LexerTokenResult *head); void clean_token_result(LexerTokenResult *head);
LexerResult lexical_analysis(LexerInfo *lexer_info);
#endif // SLS_LEXER_H #endif // SLS_LEXER_H

View File

@ -6,6 +6,8 @@
#ifndef SLS_ERROR_H #ifndef SLS_ERROR_H
#define SLS_ERROR_H #define SLS_ERROR_H
#include <stdint.h>
typedef enum { typedef enum {
FALSE, FALSE,
TRUE, TRUE,
@ -13,7 +15,7 @@ typedef enum {
typedef struct { typedef struct {
const char *message; const char *message;
int code; int32_t code;
} SlsError; } SlsError;
typedef enum { typedef enum {

View File

@ -0,0 +1,14 @@
// Kyler Olsen
// YREA SLS
// Strings Header
// November 2025
#ifndef SLS_STRING_H
#define SLS_STRING_H
#include <stddef.h>
int isascii(unsigned char c);
size_t strnlen(const char *s, size_t maxlen);
#endif // SLS_STRING_H

View File

@ -6,10 +6,11 @@
#ifndef SLS_TESTS_H #ifndef SLS_TESTS_H
#define SLS_TESTS_H #define SLS_TESTS_H
#include <stdint.h> #include <stddef.h>
#include "../sls/sls_errors.h" #include "../sls/sls_errors.h"
const char *TEST_FILE_NAME = "TEST_FILE.SLS"; extern const char *TEST_FILE_NAME;
typedef enum { typedef enum {
TEST_ERROR, TEST_ERROR,
@ -23,7 +24,7 @@ typedef struct {
const char *name; const char *name;
TestResultType status; TestResultType status;
union { union {
const char *message; // status in { TEST_LOGIC_FAIL, } char *message; // status in { TEST_LOGIC_FAIL, }
SlsError error; // status in { TEST_ERROR, TEST_ERROR_FAIL, } SlsError error; // status in { TEST_ERROR, TEST_ERROR_FAIL, }
}; };
} TestResult; } TestResult;

View File

@ -6,9 +6,55 @@
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include "sls/sls_errors.h" #include "sls/sls_errors.h"
#include "sls/lexer.h" #include "sls/lexer.h"
#include "sls/string.h"
const size_t TYPE_NAMES_SAFE_LENGTH = 20;
const char *TOKEN_TYPES_NAMES[] = {
"End of File",
"Identifier",
"Integer",
"Float",
"Double",
"String",
"Boolean",
"Array",
"Token String",
"Type Tuple",
};
const char *ARRAY_TYPES_NAMES[] = {
"Identifier",
"i64",
"i32",
"i16",
"i8",
"u64",
"u32",
"u16",
"u8",
"Float",
"Double",
"String",
"Boolean",
"Inline Struct",
};
const char *INTEGER_TYPES_NAMES[] = {
"i64",
"i32",
"i16",
"i8",
"u64",
"u32",
"u16",
"u8",
};
void init_lexer(LexerInfo *lexer_info, const char *filename, const char *source_code) { void init_lexer(LexerInfo *lexer_info, const char *filename, const char *source_code) {
lexer_info->filename = filename; lexer_info->filename = filename;

17
SLS_C/src/string.c Normal file
View File

@ -0,0 +1,17 @@
// Kyler Olsen
// YREA SLS
// String Helpers
// November 2025
#include <stddef.h>
int isascii(unsigned char c) {
return c < 128;
}
size_t strnlen(const char *s, size_t maxlen) {
size_t i;
for (i = 0; i < maxlen; i++)
if (s[i] == '\0') break;
return i;
}

View File

@ -11,9 +11,10 @@
#include "sls/sls_errors.h" #include "sls/sls_errors.h"
#include "sls/lexer.h" #include "sls/lexer.h"
#include "sls/string.h"
#include "tests/tests.h" #include "tests/tests.h"
static const size_t NUM_OF_TESTS = 12; static const size_t NUM_OF_TESTS = 14;
static const double FLOAT_TEST_PRECISION = 0.01; static const double FLOAT_TEST_PRECISION = 0.01;
@ -28,7 +29,7 @@ static LexerTest start_up_test(const char *test_name, const char *test_code) {
LexerTest test = (LexerTest) { LexerTest test = (LexerTest) {
.result = (TestResult) { .result = (TestResult) {
.name = test_name, .status = TEST_NOT_IMPLEMENTED } }; .name = test_name, .status = TEST_NOT_IMPLEMENTED } };
lexer_init(&test.lexer_info, TEST_FILE_NAME, test_code); init_lexer(&test.lexer_info, TEST_FILE_NAME, test_code);
return test; return test;
} }
@ -44,9 +45,9 @@ static TestResult error_test(LexerTest *test, LexerResult result, SlsError error
return test->result; return test->result;
} }
static TestResult logic_fail_test(LexerTest *test, LexerResult result, const char *message) { static TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message) {
if (message == 0) return error_test(test, result, (SlsError) { if (message == 0) return error_test(test, result, (SlsError) {
.message = "Out of Memory Error!", .code = 3458, }); .message = "Out of Memory Error!", .code = 1, });
clean_up_test(result); clean_up_test(result);
test->result.status = TEST_LOGIC_FAIL; test->result.status = TEST_LOGIC_FAIL;
test->result.message = message; test->result.message = message;
@ -66,6 +67,11 @@ static TestResult skip_test(LexerTest *test, LexerResult result) {
return test->result; return test->result;
} }
static TestResult skip_test_no_result(LexerTest *test) {
test->result.status = TEST_NOT_IMPLEMENTED;
return test->result;
}
static TestResult pass_test(LexerTest *test, LexerResult result) { static TestResult pass_test(LexerTest *test, LexerResult result) {
clean_up_test(result); clean_up_test(result);
test->result.status = TEST_PASS; test->result.status = TEST_PASS;
@ -76,172 +82,172 @@ static TestResult pass_test(LexerTest *test, LexerResult result) {
static char *unexpected_end_of_token_stream(size_t i) { static char *unexpected_end_of_token_stream(size_t i) {
size_t length = ceil(log10(i)) + 47; size_t length = ceil(log10(i)) + 47;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Unexpected end of token stream (%d tokens found)", i-1); snprintf(string, length, "Unexpected end of token stream (%zu tokens found)", i - 1);
return string; return string;
} }
static char *expected_end_of_token_stream(size_t i) { static char *expected_end_of_token_stream(size_t i) {
size_t length = ceil(log10(i)) + 47; size_t length = ceil(log10(i)) + 47;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Expected end of token stream (more than %d tokens found)", i-1); snprintf(string, length, "Expected end of token stream (more than %zu tokens found)", i - 1);
return string; return string;
} }
static char *token_should_be(size_t i, TokenType should, TokenType found) { static char *token_should_be(size_t i, TokenType should, TokenType found) {
size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(TOKEN_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35; size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(TOKEN_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]); snprintf(string, length, "Token #%zu should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]);
return string; return string;
} }
static char *integer_type_should_be(size_t i, TokenType should, TokenType found) { static char *integer_type_should_be(size_t i, IntegerBuiltInType should, IntegerBuiltInType found) {
size_t length = ceil(log10(i + 1)) + strnlen(INTEGER_TYPES_NAMES[should], 5) + strnlen(INTEGER_TYPES_NAMES[found], 5) + 48; size_t length = ceil(log10(i + 1)) + strnlen(INTEGER_TYPES_NAMES[should], 5) + strnlen(INTEGER_TYPES_NAMES[found], 5) + 48;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d integer type should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]); snprintf(string, length, "Token #%zu integer type should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]);
return string; return string;
} }
static char *integer_value_should_be(size_t i, uint64_t should, uint64_t found) { static char *integer_value_should_be(size_t i, uint64_t should, uint64_t found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 45; size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 45;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d integer value should be %d, but found %d", i, should, found); snprintf(string, length, "Token #%zu integer value should be %lu, but found %lu", i, should, found);
return string; return string;
} }
static char *float_value_should_be(size_t i, double should, double found) { static char *float_value_should_be(size_t i, double should, double found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 43; size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 43;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d float value should be %.2f, but found %.2f", i, should, found); snprintf(string, length, "Token #%zu float value should be %.2f, but found %.2f", i, should, found);
return string; return string;
} }
static char *identifier_should_be_literal(size_t i) { static char *identifier_should_be_literal(size_t i) {
size_t length = ceil(log10(i + 1)) + 51; size_t length = ceil(log10(i + 1)) + 51;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d identifier should be an identifier literal", i); snprintf(string, length, "Token #%zu identifier should be an identifier literal", i);
return string; return string;
} }
static char *identifier_should_not_be_literal(size_t i) { static char *identifier_should_not_be_literal(size_t i) {
size_t length = ceil(log10(i + 1)) + 55; size_t length = ceil(log10(i + 1)) + 55;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d identifier should not be an identifier literal", i); snprintf(string, length, "Token #%zu identifier should not be an identifier literal", i);
return string; return string;
} }
static char *token_length_should_be(size_t i, TokenType type, uint64_t should, uint64_t found) { static char *token_length_should_be(size_t i, TokenType type, uint64_t should, uint64_t found) {
size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 47; size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 47;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d of type %s length should be %d, but found %d", i, TOKEN_TYPES_NAMES[type], should, found); snprintf(string, length, "Token #%zu of type %s length should be %lu, but found %lu", i, TOKEN_TYPES_NAMES[type], should, found);
return string; return string;
} }
static char *token_value_string_should_be(size_t i, TokenType type, size_t value_length, const char *should, const char *found) { static char *token_value_string_should_be(size_t i, TokenType type, size_t value_length, const char *should, const char *found) {
size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 53; size_t length = ceil(log10(i + 1)) + strnlen(TOKEN_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 53;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d of type %s string value should be %s, but found %s", i, TOKEN_TYPES_NAMES[type], should, found); snprintf(string, length, "Token #%zu of type %s string value should be %s, but found %s", i, TOKEN_TYPES_NAMES[type], should, found);
return string; return string;
} }
static char *boolean_should_be(size_t i, Boolean value) { static char *boolean_should_be(size_t i, Boolean value) {
size_t length = ceil(log10(i + 1)) + 45; size_t length = ceil(log10(i + 1)) + 45;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
if (value) snprintf(string, length, "Token #%d boolean should be true, but is false", i); if (value) snprintf(string, length, "Token #%zu boolean should be true, but is false", i);
else snprintf(string, length, "Token #%d boolean should be false, but is true", i); else snprintf(string, length, "Token #%zu boolean should be false, but is true", i);
return string; return string;
} }
static char *array_type_should_be(size_t i, ArrayType should, ArrayType found) { static char *array_type_should_be(size_t i, ArrayType should, ArrayType found) {
size_t length = ceil(log10(i + 1)) + strnlen(ARRAY_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(ARRAY_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35; size_t length = ceil(log10(i + 1)) + strnlen(ARRAY_TYPES_NAMES[should], TYPE_NAMES_SAFE_LENGTH) + strnlen(ARRAY_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 35;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d should be a %s, but found a %s", i, ARRAY_TYPES_NAMES[should], ARRAY_TYPES_NAMES[found]); snprintf(string, length, "Token #%zu should be a %s, but found a %s", i, ARRAY_TYPES_NAMES[should], ARRAY_TYPES_NAMES[found]);
return string; return string;
} }
static char *array_dimensions_should_be(size_t i, size_t should, size_t found) { static char *array_dimensions_should_be(size_t i, size_t should, size_t found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 48; size_t length = ceil(log10(i + 1)) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 48;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d array dimensions should be %s, but found %s", i, should, found); snprintf(string, length, "Token #%zu array dimensions should be %zu, but found %zu", i, should, found);
return string; return string;
} }
static char *array_element_shape_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) { static char *array_element_shape_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 63; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 63;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d dimension %d of array type %s should be shape %d, but found %d", i, j, TOKEN_TYPES_NAMES[type], should, found); snprintf(string, length, "Token #%zu dimension %zu of array type %s should be shape %lu, but found %lu", i, j, TOKEN_TYPES_NAMES[type], should, found);
return string; return string;
} }
static char *array_element_integer_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) { static char *array_element_integer_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 55; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 55;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d element %d of array type %s should be %d, but found %d", i, j, TOKEN_TYPES_NAMES[type], should, found); snprintf(string, length, "Token #%zu element %zu of array type %s should be %lu, but found %lu", i, j, TOKEN_TYPES_NAMES[type], should, found);
return string; return string;
} }
static char *array_element_float_should_be(size_t i, size_t j, ArrayType type, double should, double found) { static char *array_element_float_should_be(size_t i, size_t j, ArrayType type, double should, double found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 55; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + ceil(log10(should + 1)) + ceil(log10(found + 1)) + 55;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d element %d of array type %s should be %.2f, but found %.2f", i, j, TOKEN_TYPES_NAMES[type], should, found); snprintf(string, length, "Token #%zu element %zu of array type %s should be %.2f, but found %.2f", i, j, TOKEN_TYPES_NAMES[type], should, found);
return string; return string;
} }
static char *array_element_string_should_be(size_t i, size_t j, ArrayType type, size_t value_length, const char *should, const char *found) { static char *array_element_string_should_be(size_t i, size_t j, ArrayType type, size_t value_length, const char *should, const char *found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 55; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + strnlen(should, value_length) + strnlen(found, value_length) + 55;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d element %d of array type %s should be %s, but found %s", i, j, TOKEN_TYPES_NAMES[type], should, found); snprintf(string, length, "Token #%zu element %zu of array type %s should be %s, but found %s", i, j, TOKEN_TYPES_NAMES[type], should, found);
return string; return string;
} }
static char *array_element_boolean_should_be(size_t i, size_t j, ArrayType type, Boolean value) { static char *array_element_boolean_should_be(size_t i, size_t j, ArrayType type, Boolean value) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + 64; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(ARRAY_TYPES_NAMES[type], TYPE_NAMES_SAFE_LENGTH) + 64;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
if (value) snprintf(string, length, "Token #%d element %d of array type %s should be true, but found false", i, j, TOKEN_TYPES_NAMES[type]); if (value) snprintf(string, length, "Token #%zu element %zu of array type %s should be true, but found false", i, j, TOKEN_TYPES_NAMES[type]);
else snprintf(string, length, "Token #%d element %d of array type %s should be false, but found true", i, j, TOKEN_TYPES_NAMES[type]); else snprintf(string, length, "Token #%zu element %zu of array type %s should be false, but found true", i, j, TOKEN_TYPES_NAMES[type]);
return string; return string;
} }
static char *type_tuple_element_integer_should_be(size_t i, size_t j, uint64_t should, uint64_t found) { static char *type_tuple_element_integer_should_be(size_t i, size_t j, uint64_t should, uint64_t found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 54; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + ceil(log10(should + 1) + 3) + ceil(log10(found + 1) + 3) + 54;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d element %d of type tuple should be %d, but found %d", i, j, should, found); snprintf(string, length, "Token #%zu element %zu of type tuple should be %lu, but found %lu", i, j, should, found);
return string; return string;
} }
static char *type_tuple_element_string_should_be(size_t i, size_t j, size_t value_length, const char *should, const char *found) { static char *type_tuple_element_string_should_be(size_t i, size_t j, size_t value_length, const char *should, const char *found) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(should, value_length) + strnlen(found, value_length) + 54; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(should, value_length) + strnlen(found, value_length) + 54;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
snprintf(string, length, "Token #%d element %d of type tuple should be %s, but found %s", i, j, should, found); snprintf(string, length, "Token #%zu element %zu of type tuple should be %s, but found %s", i, j, should, found);
return string; return string;
} }
static char *type_tuple_element_boolean_should_be(size_t i, size_t j, Boolean value) { static char *type_tuple_element_boolean_should_be(size_t i, size_t j, Boolean value) {
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + 63; size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + 63;
char *string = malloc(sizeof(char) * length); char *string = (char *)malloc(sizeof(char) * length);
if (string = 0) return string; if (string == 0) return string;
if (value) snprintf(string, length, "Token #%d element %d of type tuple should be true, but found false", i, j); if (value) snprintf(string, length, "Token #%zu element %zu of type tuple should be true, but found false", i, j);
else snprintf(string, length, "Token #%d element %d of type tuple should be false, but found true", i, j); else snprintf(string, length, "Token #%zu element %zu of type tuple should be false, but found true", i, j);
return string; return string;
} }
@ -253,7 +259,7 @@ static Boolean test_token_type(LexerTest *test, LexerResult result, size_t i, To
logic_fail_test(test, result, unexpected_end_of_token_stream(i + 1)); logic_fail_test(test, result, unexpected_end_of_token_stream(i + 1));
return TRUE; return TRUE;
} if (head->type == SLS_ERROR) { } if (head->type == SLS_ERROR) {
error_fail_test(test, result, result.error); error_fail_test(test, result, head->error);
return TRUE; return TRUE;
} if (head->result.type != token_type) { } if (head->result.type != token_type) {
logic_fail_test(test, result, token_should_be(i + 1, token_type, head->result.type)); logic_fail_test(test, result, token_should_be(i + 1, token_type, head->result.type));
@ -273,7 +279,7 @@ static Boolean test_array_type(LexerTest *test, LexerResult result, size_t i, Ar
logic_fail_test(test, result, array_dimensions_should_be(i + 1, dimensions, head->result.array_literal.dimensions)); logic_fail_test(test, result, array_dimensions_should_be(i + 1, dimensions, head->result.array_literal.dimensions));
return TRUE; return TRUE;
} }
for (int j = 0; j < dimensions; j++) { for (size_t j = 0; j < dimensions; j++) {
if (head->result.array_literal.shape[j] != shape[j]) { if (head->result.array_literal.shape[j] != shape[j]) {
logic_fail_test(test, result, array_element_shape_should_be(i + 1, j, array_type, shape[j], head->result.array_literal.shape[j])); logic_fail_test(test, result, array_element_shape_should_be(i + 1, j, array_type, shape[j], head->result.array_literal.shape[j]));
return TRUE; return TRUE;
@ -283,6 +289,7 @@ static Boolean test_array_type(LexerTest *test, LexerResult result, size_t i, Ar
} }
static Boolean test_eof_value(LexerTest *test, LexerResult result, size_t i, void *_) { static Boolean test_eof_value(LexerTest *test, LexerResult result, size_t i, void *_) {
(void)_; // We don't use this anywhere in this function
static const TokenType token_type = TOKEN_EOF; static const TokenType token_type = TOKEN_EOF;
LexerTokenResult *head = get_token(result.result, i); LexerTokenResult *head = get_token(result.result, i);
if (test_token_type(test, result, i, token_type)) { if (test_token_type(test, result, i, token_type)) {
@ -407,8 +414,8 @@ static Boolean test_array_identifier_value(LexerTest *test, LexerResult result,
return TRUE; return TRUE;
} }
size_t length = 1; size_t length = 1;
for (int j = 0; j < values->dimensions; j++) length *= values->shape[j]; for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (int j = 0; j < length; j++) { for (size_t j = 0; j < length; j++) {
if (head->result.array_literal.identifiers[j].length == values->values[j].length) { if (head->result.array_literal.identifiers[j].length == values->values[j].length) {
logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.identifiers[j].length)); logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.identifiers[j].length));
return TRUE; return TRUE;
@ -436,8 +443,8 @@ static Boolean test_array_integer_value(LexerTest *test, LexerResult result, siz
return TRUE; return TRUE;
} }
size_t length = 1; size_t length = 1;
for (int j = 0; j < values->dimensions; j++) length *= values->shape[j]; for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (int j = 0; j < length; j++) { for (size_t j = 0; j < length; j++) {
if (head->result.array_literal.integer_literals[j] == values->values[j].value) { if (head->result.array_literal.integer_literals[j] == values->values[j].value) {
logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].value, head->result.array_literal.integer_literals[j])); logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].value, head->result.array_literal.integer_literals[j]));
return TRUE; return TRUE;
@ -459,8 +466,8 @@ static Boolean test_array_float_value(LexerTest *test, LexerResult result, size_
return TRUE; return TRUE;
} }
size_t length = 1; size_t length = 1;
for (int j = 0; j < values->dimensions; j++) length *= values->shape[j]; for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (int j = 0; j < length; j++) { for (size_t j = 0; j < length; j++) {
if (fabsf(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) { if (fabsf(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) {
logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j])); logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j]));
return TRUE; return TRUE;
@ -482,8 +489,8 @@ static Boolean test_array_double_value(LexerTest *test, LexerResult result, size
return TRUE; return TRUE;
} }
size_t length = 1; size_t length = 1;
for (int j = 0; j < values->dimensions; j++) length *= values->shape[j]; for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (int j = 0; j < length; j++) { for (size_t j = 0; j < length; j++) {
if (fabs(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) { if (fabs(head->result.array_literal.float_literals[j] - values->values[j]) >= FLOAT_TEST_PRECISION) {
logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j])); logic_fail_test(test, result, array_element_float_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.float_literals[j]));
return TRUE; return TRUE;
@ -505,8 +512,8 @@ static Boolean test_array_string_value(LexerTest *test, LexerResult result, size
return TRUE; return TRUE;
} }
size_t length = 1; size_t length = 1;
for (int j = 0; j < values->dimensions; j++) length *= values->shape[j]; for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (int j = 0; j < length; j++) { for (size_t j = 0; j < length; j++) {
if (head->result.array_literal.string_literals[j].length == values->values[j].length) { if (head->result.array_literal.string_literals[j].length == values->values[j].length) {
logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.string_literals[j].length)); logic_fail_test(test, result, array_element_integer_should_be(i + 1, j, array_type, values->values[j].length, head->result.array_literal.string_literals[j].length));
return TRUE; return TRUE;
@ -531,8 +538,8 @@ static Boolean test_array_boolean_value(LexerTest *test, LexerResult result, siz
return TRUE; return TRUE;
} }
size_t length = 1; size_t length = 1;
for (int j = 0; j < values->dimensions; j++) length *= values->shape[j]; for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (int j = 0; j < length; j++) { for (size_t j = 0; j < length; j++) {
if (head->result.array_literal.boolean_literals[j] == values->values[j]) { if (head->result.array_literal.boolean_literals[j] == values->values[j]) {
logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, values->values[j])); logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, values->values[j]));
return TRUE; return TRUE;
@ -556,12 +563,12 @@ static Boolean test_array_struct_inline_value(LexerTest *test, LexerResult resul
if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) { if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) {
return TRUE; return TRUE;
} if (strncmp(head->result.array_literal.struct_inline.name, values->struct_name, values->struct_name_length)) { } if (strncmp(head->result.array_literal.struct_inline.name, values->struct_name, values->struct_name_length)) {
logic_fail_test(test, result, token_value_string_should_be(i + 1, ARRAY_STRUCT_INLINE, values->struct_name_length, values->struct_name, head->result.array_literal.struct_inline.name)); logic_fail_test(test, result, token_value_string_should_be(i + 1, TOKEN_IDENTIFIER, values->struct_name_length, values->struct_name, head->result.array_literal.struct_inline.name));
return TRUE; return TRUE;
} }
size_t length = 1; size_t length = 1;
for (int j = 0; j < values->dimensions; j++) length *= values->shape[j]; for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (int j = 0; j < length; j++) { for (size_t j = 0; j < length; j++) {
if (values->struct_handler(test, result, i, j, head->result.array_literal.struct_inline.values[j], values->values[j])) { if (values->struct_handler(test, result, i, j, head->result.array_literal.struct_inline.values[j], values->values[j])) {
return TRUE; return TRUE;
} }
@ -582,10 +589,10 @@ typedef struct {
static LexerResult token_string_to_lexer_result(TokenString token_string, FileInfo file_info) { static LexerResult token_string_to_lexer_result(TokenString token_string, FileInfo file_info) {
LexerTokenResult *new, *head; LexerTokenResult *new, *head;
head = 0; head = 0;
// head = malloc(sizeof(LexerTokenResult)); // head = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
// *head = (LexerTokenResult) { .type = SLS_RESULT, .result = (Token) { .type = TOKEN_EOF }, .file_info = file_info, .next = 0 }; // *head = (LexerTokenResult) { .type = SLS_RESULT, .result = (Token) { .type = TOKEN_EOF }, .file_info = file_info, .next = 0 };
for (int i = 0; i> token_string.length; i++) { for (size_t i = 0; i> token_string.length; i++) {
new = malloc(sizeof(LexerTokenResult)); new = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
*new = (LexerTokenResult) { .type = SLS_RESULT, .result = token_string.tokens[i], .file_info = file_info, .next = head }; *new = (LexerTokenResult) { .type = SLS_RESULT, .result = token_string.tokens[i], .file_info = file_info, .next = head };
head = new; head = new;
} }
@ -601,7 +608,7 @@ static Boolean test_token_string_value(LexerTest *test, LexerResult result, size
logic_fail_test(test, result, integer_value_should_be(i + 1, values->tokens, head->result.token_string.length)); logic_fail_test(test, result, integer_value_should_be(i + 1, values->tokens, head->result.token_string.length));
return TRUE; return TRUE;
} }
for (int j = 0; j < values->tokens; j++) { for (size_t j = 0; j < values->tokens; j++) {
LexerResult token_string_result = token_string_to_lexer_result(head->result.token_string, head->file_info); LexerResult token_string_result = token_string_to_lexer_result(head->result.token_string, head->file_info);
if (values->values[j].token_handler(test, token_string_result, j, values->values[j].value)) { if (values->values[j].token_handler(test, token_string_result, j, values->values[j].value)) {
clean_token_result(token_string_result.result); clean_token_result(token_string_result.result);
@ -630,7 +637,7 @@ static Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t
} if (head->result.type_tuple.output_length != values->output_length) { } if (head->result.type_tuple.output_length != values->output_length) {
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, values->output_length, head->result.type_tuple.output_length)); logic_fail_test(test, result, token_length_should_be(i + 1, token_type, values->output_length, head->result.type_tuple.output_length));
return TRUE; return TRUE;
} for (int j = 0; j < values->input_length; j++) { } for (size_t j = 0; j < values->input_length; j++) {
if (head->result.type_tuple.input_identifiers[j].length == values->input_values[j].length) { if (head->result.type_tuple.input_identifiers[j].length == values->input_values[j].length) {
logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->input_values[j].length, head->result.type_tuple.input_identifiers[j].length)); logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->input_values[j].length, head->result.type_tuple.input_identifiers[j].length));
return TRUE; return TRUE;
@ -641,7 +648,7 @@ static Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t
logic_fail_test(test, result, type_tuple_element_boolean_should_be(i + 1, j, TRUE)); logic_fail_test(test, result, type_tuple_element_boolean_should_be(i + 1, j, TRUE));
return TRUE; return TRUE;
} }
} for (int j = 0; j < values->output_length; j++) { } for (size_t j = 0; j < values->output_length; j++) {
if (head->result.type_tuple.output_identifiers[j].length == values->output_values[j].length) { if (head->result.type_tuple.output_identifiers[j].length == values->output_values[j].length) {
logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->output_values[j].length, head->result.type_tuple.output_identifiers[j].length)); logic_fail_test(test, result, type_tuple_element_integer_should_be(i + 1, j, values->output_values[j].length, head->result.type_tuple.output_identifiers[j].length));
return TRUE; return TRUE;
@ -658,6 +665,15 @@ static Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t
// Test cases // Test cases
static TestResult test_empty_statement() {
LexerTest test = start_up_test("test_empty_statement", "");
LexerResult result = lexical_analysis(&test.lexer_info);
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
size_t i = 0;
if (test_eof_value(&test, result, i++, 0)) return test.result;
return pass_test(&test, result);
}
static TestResult test_hello_world_statement() { static TestResult test_hello_world_statement() {
LexerTest test = start_up_test("test_hello_world_statement", "\"Hello, World!\" print"); LexerTest test = start_up_test("test_hello_world_statement", "\"Hello, World!\" print");
LexerResult result = lexical_analysis(&test.lexer_info); LexerResult result = lexical_analysis(&test.lexer_info);
@ -750,8 +766,8 @@ static TestResult test_square_fn() {
size_t i = 0; size_t i = 0;
if (test_type_tuple_value(&test, result, i++, &(TestTypeTupleValue){1, (TestIdentifierValue[]){(TestIdentifierValue){TRUE, 6, "Number"}}, 1, (TestIdentifierValue[]){(TestIdentifierValue){TRUE, 6, "Number"}}})) return test.result; if (test_type_tuple_value(&test, result, i++, &(TestTypeTupleValue){1, (TestIdentifierValue[]){(TestIdentifierValue){TRUE, 6, "Number"}}, 1, (TestIdentifierValue[]){(TestIdentifierValue){TRUE, 6, "Number"}}})) return test.result;
if (test_token_string_value(&test, result, i++, &(TestTokenStringValue){3, (TestTokenStringToken[]){ if (test_token_string_value(&test, result, i++, &(TestTokenStringValue){3, (TestTokenStringToken[]){
(TestTokenStringToken){test_identifier_value, &(TestIdentifierValue){FALSE, 3, "dup"}}, (TestTokenStringToken){(Boolean (*)(LexerTest *, LexerResult, size_t, void *))test_identifier_value, &(TestIdentifierValue){FALSE, 3, "dup"}},
(TestTokenStringToken){test_identifier_value, &(TestIdentifierValue){FALSE, 1, "*"}} (TestTokenStringToken){(Boolean (*)(LexerTest *, LexerResult, size_t, void *))test_identifier_value, &(TestIdentifierValue){FALSE, 1, "*"}}
}})) return test.result; }})) return test.result;
if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){TRUE, 6, "square"})) return test.result; if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){TRUE, 6, "square"})) return test.result;
if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 2, "fn"})) return test.result; if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 2, "fn"})) return test.result;
@ -825,11 +841,12 @@ TestsReport run_lexer_tests() {
TestsReport test_report = (TestsReport) { TestsReport test_report = (TestsReport) {
.section = "lexer_tests", .section = "lexer_tests",
.count = NUM_OF_TESTS, .count = NUM_OF_TESTS,
.tests = malloc(sizeof(TestResult) * NUM_OF_TESTS), .tests = (TestResult *)malloc(sizeof(TestResult) * NUM_OF_TESTS),
}; };
size_t i = 0; size_t i = 0;
test_report.tests[i++] = test_empty_statement();
test_report.tests[i++] = test_hello_world_statement(); test_report.tests[i++] = test_hello_world_statement();
test_report.tests[i++] = test_add_statement(); test_report.tests[i++] = test_add_statement();
test_report.tests[i++] = test_sub_statement(); test_report.tests[i++] = test_sub_statement();
@ -837,6 +854,7 @@ TestsReport run_lexer_tests() {
test_report.tests[i++] = test_div_statement(); test_report.tests[i++] = test_div_statement();
test_report.tests[i++] = test_add_and_mult_statement(); test_report.tests[i++] = test_add_and_mult_statement();
test_report.tests[i++] = test_dup_and_mult_statement(); test_report.tests[i++] = test_dup_and_mult_statement();
test_report.tests[i++] = test_square_fn();
test_report.tests[i++] = test_dup_statement(); test_report.tests[i++] = test_dup_statement();
test_report.tests[i++] = test_swap_statement(); test_report.tests[i++] = test_swap_statement();
test_report.tests[i++] = test_over_statement(); test_report.tests[i++] = test_over_statement();

View File

@ -4,27 +4,37 @@
// November 2025 // November 2025
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tests/tests.h" #include "tests/tests.h"
const char *TEST_FILE_NAME = "TEST_FILE.SLS";
int main(void) { int main(void) {
TestsReport lexer_reports = run_lexer_tests(); TestsReport lexer_reports = run_lexer_tests();
for (int i = 0; i < lexer_reports.count; i++) { for (size_t i = 0; i < lexer_reports.count; i++) {
switch (lexer_reports.tests[i].status) { switch (lexer_reports.tests[i].status) {
case TEST_ERROR: case TEST_ERROR:
// Bright Red
printf("\x1b[91mTest errored: %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].error.message); printf("\x1b[91mTest errored: %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].error.message);
break; break;
case TEST_ERROR_FAIL: case TEST_ERROR_FAIL:
// Magenta
printf("\x1b[35mTest failed (errored): %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].error.message); printf("\x1b[35mTest failed (errored): %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].error.message);
break; break;
case TEST_LOGIC_FAIL: case TEST_LOGIC_FAIL:
// Red
printf("\x1b[31mTest failed: %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].message); printf("\x1b[31mTest failed: %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].message);
free(lexer_reports.tests[i].message);
break; break;
case TEST_PASS: case TEST_PASS:
// Green
printf("\x1b[32mTest passed: %s\n\x1b[0m", lexer_reports.tests[i].name); printf("\x1b[32mTest passed: %s\n\x1b[0m", lexer_reports.tests[i].name);
break; break;
case TEST_NOT_IMPLEMENTED: case TEST_NOT_IMPLEMENTED:
// Blue
printf("\x1b[34mTest not implemented: %s\n\x1b[0m", lexer_reports.tests[i].name); printf("\x1b[34mTest not implemented: %s\n\x1b[0m", lexer_reports.tests[i].name);
break; break;
} }