Merge branch 'master' into numeric_literals
This commit is contained in:
commit
f921b58359
|
|
@ -1,9 +1,9 @@
|
||||||
# Makefile for SLS project with automatic header dependencies
|
# Makefile for SLS project with automatic header dependencies
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS ?= -std=c11 -Wall -Wextra -g -Iinclude -MMD -MP
|
CFLAGS ?= -std=c99 -Wall -Wextra -g -Iinclude -MMD -MP
|
||||||
LDFLAGS ?=
|
LDFLAGS ?=
|
||||||
CTESTFLAGS ?= -std=c11 -Wall -Wextra -Wno-unused-function -g -O0 -Iinclude -MMD -MP
|
CTESTFLAGS ?= -std=c99 -Wall -Wextra -Wno-unused-function -g -O0 -Iinclude -MMD -MP
|
||||||
|
|
||||||
SRCDIR := src
|
SRCDIR := src
|
||||||
OBJDIR := obj
|
OBJDIR := obj
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Sls String
|
||||||
|
*string.h*
|
||||||
|
|
||||||
|
## Formats
|
||||||
|
|
||||||
|
- `y` char\*
|
||||||
|
- `c` char
|
||||||
|
- `d` int32_t
|
||||||
|
- `l` int64_t
|
||||||
|
- `u` uint64_t
|
||||||
|
- `z` size_t
|
||||||
|
- `f` double
|
||||||
|
- `s` string.h SlsStr
|
||||||
|
- `t` lexer.h TokenType
|
||||||
|
- `a` lexer.h ArrayType
|
||||||
|
- `i` lexer.h IntegerBuiltInType
|
||||||
|
- `e` error.h SlsError
|
||||||
|
- `b` bool.h Boolean
|
||||||
|
|
@ -9,8 +9,10 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "./string.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *message;
|
SlsStr message;
|
||||||
int32_t code;
|
int32_t code;
|
||||||
} SlsError;
|
} SlsError;
|
||||||
|
|
||||||
|
|
@ -20,7 +22,7 @@ typedef enum {
|
||||||
} SlsResultType;
|
} SlsResultType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *filename;
|
SlsStr filename;
|
||||||
size_t line;
|
size_t line;
|
||||||
size_t column;
|
size_t column;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
extern const size_t TYPE_NAMES_SAFE_LENGTH;
|
extern const size_t TYPE_NAMES_SAFE_LENGTH;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *filename;
|
SlsStr filename;
|
||||||
const char *source_code;
|
SlsStr source_code;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
size_t column;
|
size_t column;
|
||||||
size_t line;
|
size_t line;
|
||||||
|
|
@ -56,8 +56,7 @@ typedef enum {
|
||||||
extern const char *ARRAY_TYPES_NAMES[];
|
extern const char *ARRAY_TYPES_NAMES[];
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
SlsStr name;
|
||||||
size_t length;
|
|
||||||
Boolean is_literal;
|
Boolean is_literal;
|
||||||
} Identifier;
|
} Identifier;
|
||||||
|
|
||||||
|
|
@ -79,11 +78,6 @@ typedef struct {
|
||||||
IntegerBuiltInType type;
|
IntegerBuiltInType type;
|
||||||
} IntegerLiteral;
|
} IntegerLiteral;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *value;
|
|
||||||
size_t length;
|
|
||||||
} StringLiteral;
|
|
||||||
|
|
||||||
typedef struct Token Token;
|
typedef struct Token Token;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -100,7 +94,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void **values;
|
void **values;
|
||||||
const char *name;
|
SlsStr name;
|
||||||
} StructInline;
|
} StructInline;
|
||||||
|
|
||||||
typedef struct ArrayLiteral {
|
typedef struct ArrayLiteral {
|
||||||
|
|
@ -110,7 +104,7 @@ typedef struct ArrayLiteral {
|
||||||
uint64_t *integer_literals; // type in { ARRAY_I64, ARRAY_I32, ARRAY_I16, ARRAY_I8, ARRAY_U64, ARRAY_U32, ARRAY_U16, ARRAY_U8, }
|
uint64_t *integer_literals; // type in { ARRAY_I64, ARRAY_I32, ARRAY_I16, ARRAY_I8, ARRAY_U64, ARRAY_U32, ARRAY_U16, ARRAY_U8, }
|
||||||
float *float_literals; // type == ARRAY_FLOAT
|
float *float_literals; // type == ARRAY_FLOAT
|
||||||
double *double_literals; // type == ARRAY_DOUBLE
|
double *double_literals; // type == ARRAY_DOUBLE
|
||||||
StringLiteral *string_literals; // type == ARRAY_STRING
|
SlsStr *string_literals; // type == ARRAY_STRING
|
||||||
Boolean *boolean_literals; // type == ARRAY_BOOLEAN
|
Boolean *boolean_literals; // type == ARRAY_BOOLEAN
|
||||||
TokenString *token_strings; // type == ARRAY_TOKEN_STRING
|
TokenString *token_strings; // type == ARRAY_TOKEN_STRING
|
||||||
TypeTuple *type_tuples; // type == ARRAY_TYPE_TUPLE
|
TypeTuple *type_tuples; // type == ARRAY_TYPE_TUPLE
|
||||||
|
|
@ -127,7 +121,7 @@ struct Token {
|
||||||
IntegerLiteral integer_literal; // type == TOKEN_INTEGER
|
IntegerLiteral integer_literal; // type == TOKEN_INTEGER
|
||||||
float float_literal; // type == TOKEN_FLOAT
|
float float_literal; // type == TOKEN_FLOAT
|
||||||
double double_literal; // type == TOKEN_DOUBLE
|
double double_literal; // type == TOKEN_DOUBLE
|
||||||
StringLiteral string_literal; // type == TOKEN_STRING
|
SlsStr string_literal; // type == TOKEN_STRING
|
||||||
Boolean boolean_literal; // type == TOKEN_BOOLEAN
|
Boolean boolean_literal; // type == TOKEN_BOOLEAN
|
||||||
ArrayLiteral array_literal; // type == TOKEN_ARRAY
|
ArrayLiteral array_literal; // type == TOKEN_ARRAY
|
||||||
TokenString token_string; // type == TOKEN_TOKEN_STRING
|
TokenString token_string; // type == TOKEN_TOKEN_STRING
|
||||||
|
|
@ -153,7 +147,7 @@ typedef struct {
|
||||||
};
|
};
|
||||||
} LexerResult;
|
} LexerResult;
|
||||||
|
|
||||||
void init_lexer(LexerInfo *lexer_info, const char *filename, const char *source_code);
|
void init_lexer(LexerInfo *lexer_info, SlsStr filename, SlsStr source_code);
|
||||||
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);
|
LexerResult lexical_analysis(LexerInfo *lexer_info);
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,27 @@
|
||||||
#define SLS_STRING_H
|
#define SLS_STRING_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "bool.h"
|
#include "bool.h"
|
||||||
|
|
||||||
int isascii(unsigned char c);
|
typedef struct {
|
||||||
size_t strnlen(const char *s, size_t maxlen);
|
size_t len; // Number of useable characters (does not include trailing null character)
|
||||||
|
char *str;
|
||||||
|
Boolean allocated;
|
||||||
|
} SlsStr;
|
||||||
|
|
||||||
|
#define SLS_STR(s) (SlsStr){ sizeof(s) - 1, (s), FALSE }
|
||||||
|
#define SLS_STR_NULL (SlsStr){0, NULL, FALSE}
|
||||||
|
|
||||||
|
int sls_isascii(unsigned char c);
|
||||||
|
size_t sls_str_nlen(const char *s, size_t maxlen);
|
||||||
|
SlsStr sls_str_malloc(const char *s, size_t maxlen);
|
||||||
|
SlsStr sls_str_new(size_t length);
|
||||||
|
SlsStr sls_str_cpy(SlsStr s);
|
||||||
|
int32_t sls_str_cmp(SlsStr a, SlsStr b);
|
||||||
|
void sls_str_free(SlsStr *s);
|
||||||
|
SlsStr sls_format(const SlsStr s, ...);
|
||||||
|
|
||||||
#endif // SLS_STRING_H
|
#endif // SLS_STRING_H
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Boolean is_literal;
|
Boolean is_literal;
|
||||||
size_t length;
|
SlsStr name;
|
||||||
const char *name;
|
|
||||||
} TestIdentifierValue;
|
} TestIdentifierValue;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -37,11 +36,6 @@ typedef struct {
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
} TestIntegerValue;
|
} TestIntegerValue;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
size_t length;
|
|
||||||
const char *string;
|
|
||||||
} TestStringValue;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t dimensions;
|
size_t dimensions;
|
||||||
size_t *shape;
|
size_t *shape;
|
||||||
|
|
@ -69,7 +63,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t dimensions;
|
size_t dimensions;
|
||||||
size_t *shape;
|
size_t *shape;
|
||||||
TestStringValue *values;
|
SlsStr *values;
|
||||||
} TestArrayStringValue;
|
} TestArrayStringValue;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -81,8 +75,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t dimensions;
|
size_t dimensions;
|
||||||
size_t *shape;
|
size_t *shape;
|
||||||
size_t struct_name_length;
|
SlsStr struct_name;
|
||||||
const char *struct_name;
|
|
||||||
Boolean (*struct_handler)(LexerTest *, LexerResult, size_t, size_t, void *, void *);
|
Boolean (*struct_handler)(LexerTest *, LexerResult, size_t, size_t, void *, void *);
|
||||||
void **values;
|
void **values;
|
||||||
} TestArrayStructInlineValue;
|
} TestArrayStructInlineValue;
|
||||||
|
|
@ -104,15 +97,11 @@ typedef struct {
|
||||||
TestIdentifierValue *output_values;
|
TestIdentifierValue *output_values;
|
||||||
} TestTypeTupleValue;
|
} TestTypeTupleValue;
|
||||||
|
|
||||||
typedef struct {
|
LexerTest start_up_test(SlsStr test_name, SlsStr test_code);
|
||||||
size_t length;
|
|
||||||
const char *message;
|
|
||||||
} TestErrorMessage;
|
|
||||||
|
|
||||||
LexerTest start_up_test(const char *test_name, const char *test_code);
|
|
||||||
void clean_up_test(LexerResult result);
|
void clean_up_test(LexerResult result);
|
||||||
|
TestResult error_test_out_of_mem(LexerTest *test);
|
||||||
TestResult error_test(LexerTest *test, LexerResult result, SlsError error);
|
TestResult error_test(LexerTest *test, LexerResult result, SlsError error);
|
||||||
TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message);
|
TestResult logic_fail_test(LexerTest *test, LexerResult result, SlsStr message);
|
||||||
TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error);
|
TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error);
|
||||||
TestResult skip_test(LexerTest *test, LexerResult result);
|
TestResult skip_test(LexerTest *test, LexerResult result);
|
||||||
TestResult skip_test_no_result(LexerTest *test);
|
TestResult skip_test_no_result(LexerTest *test);
|
||||||
|
|
@ -123,7 +112,7 @@ Boolean test_identifier_value(LexerTest *test, LexerResult result, size_t i, Tes
|
||||||
Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, TestIntegerValue *value);
|
Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, TestIntegerValue *value);
|
||||||
Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value);
|
Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value);
|
||||||
Boolean test_double_value(LexerTest *test, LexerResult result, size_t i, double *value);
|
Boolean test_double_value(LexerTest *test, LexerResult result, size_t i, double *value);
|
||||||
Boolean test_string_value(LexerTest *test, LexerResult result, size_t i, TestStringValue *value);
|
Boolean test_string_value(LexerTest *test, LexerResult result, size_t i, SlsStr value);
|
||||||
Boolean test_boolean_value(LexerTest *test, LexerResult result, size_t i, Boolean *value);
|
Boolean test_boolean_value(LexerTest *test, LexerResult result, size_t i, Boolean *value);
|
||||||
Boolean test_array_identifier_value(LexerTest *test, LexerResult result, size_t i, TestArrayIdentifierValue *values);
|
Boolean test_array_identifier_value(LexerTest *test, LexerResult result, size_t i, TestArrayIdentifierValue *values);
|
||||||
Boolean test_array_integer_value(LexerTest *test, LexerResult result, size_t i, TestArrayIntegerValue *values);
|
Boolean test_array_integer_value(LexerTest *test, LexerResult result, size_t i, TestArrayIntegerValue *values);
|
||||||
|
|
@ -134,6 +123,6 @@ Boolean test_array_boolean_value(LexerTest *test, LexerResult result, size_t i,
|
||||||
Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size_t i, TestArrayStructInlineValue *values);
|
Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size_t i, TestArrayStructInlineValue *values);
|
||||||
Boolean test_token_string_value(LexerTest *test, LexerResult result, size_t i, TestTokenStringValue *values);
|
Boolean test_token_string_value(LexerTest *test, LexerResult result, size_t i, TestTokenStringValue *values);
|
||||||
Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, TestTypeTupleValue *values);
|
Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, TestTypeTupleValue *values);
|
||||||
Boolean test_for_error(LexerTest *test, LexerResult result, size_t i, TestErrorMessage *error);
|
Boolean test_for_error(LexerTest *test, LexerResult result, size_t i, SlsStr error);
|
||||||
|
|
||||||
#endif // SLS_LEXER_TEST_HELPERS_H
|
#endif // SLS_LEXER_TEST_HELPERS_H
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "sls/errors.h"
|
#include "sls/errors.h"
|
||||||
|
#include "sls/string.h"
|
||||||
|
|
||||||
extern const char *TEST_FILE_NAME;
|
extern const SlsStr TEST_FILE_NAME;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TEST_ERROR, // The test encountered an error
|
TEST_ERROR, // The test encountered an error
|
||||||
|
|
@ -22,20 +23,21 @@ typedef enum {
|
||||||
} TestResultType;
|
} TestResultType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
SlsStr name;
|
||||||
TestResultType status;
|
TestResultType status;
|
||||||
union {
|
union {
|
||||||
char *message; // status in { TEST_LOGIC_FAIL, }
|
SlsStr 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;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *section;
|
SlsStr section;
|
||||||
size_t count;
|
size_t count;
|
||||||
TestResult* tests;
|
TestResult* tests;
|
||||||
} TestsReport;
|
} TestsReport;
|
||||||
|
|
||||||
|
TestsReport run_string_tests();
|
||||||
TestsReport run_lexer_tests();
|
TestsReport run_lexer_tests();
|
||||||
|
|
||||||
#endif // SLS_TESTS_H
|
#endif // SLS_TESTS_H
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ const char *INTEGER_TYPES_NAMES[] = {
|
||||||
"u8",
|
"u8",
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_lexer(LexerInfo *lexer_info, const char *filename, const char *source_code) {
|
void init_lexer(LexerInfo *lexer_info, SlsStr filename, SlsStr source_code) {
|
||||||
// Initializes a LexerInfo struct with file info and source code
|
// Initializes a LexerInfo struct with file info and source code
|
||||||
lexer_info->filename = filename;
|
lexer_info->filename = filename;
|
||||||
lexer_info->source_code = source_code;
|
lexer_info->source_code = source_code;
|
||||||
|
|
@ -81,27 +81,27 @@ static FileInfo get_file_info(LexerInfo *lexer_info, size_t start, size_t start_
|
||||||
|
|
||||||
static const char *get_token_text(LexerInfo *lexer_info, size_t start) {
|
static const char *get_token_text(LexerInfo *lexer_info, size_t start) {
|
||||||
// Returns the current character from the source code
|
// Returns the current character from the source code
|
||||||
return lexer_info->source_code + start;
|
return lexer_info->source_code.str + start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char peek(LexerInfo *lexer_info) {
|
static char peek(LexerInfo *lexer_info) {
|
||||||
// Returns the current character from the source code
|
// Returns the current character from the source code
|
||||||
return lexer_info->source_code[lexer_info->pos];
|
return lexer_info->source_code.str[lexer_info->pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char far_peek(LexerInfo *lexer_info, size_t index) {
|
static char far_peek(LexerInfo *lexer_info, size_t index) {
|
||||||
// Returns the character index away from the current char in the source code
|
// Returns the character index away from the current char in the source code
|
||||||
return lexer_info->source_code[lexer_info->pos + index];
|
return lexer_info->source_code.str[lexer_info->pos + index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char seek(LexerInfo *lexer_info, size_t index) {
|
static char seek(LexerInfo *lexer_info, size_t index) {
|
||||||
// Returns the character from the given index from the source code
|
// Returns the character from the given index from the source code
|
||||||
return lexer_info->source_code[index];
|
return lexer_info->source_code.str[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char advance(LexerInfo *lexer_info) {
|
static char advance(LexerInfo *lexer_info) {
|
||||||
// Advances lexer_info to the next character
|
// Advances lexer_info to the next character
|
||||||
if (lexer_info->source_code[lexer_info->pos] == '\n') {
|
if (lexer_info->source_code.str[lexer_info->pos] == '\n') {
|
||||||
// If a new line is encountered, advance line and reset column
|
// If a new line is encountered, advance line and reset column
|
||||||
lexer_info->line++;
|
lexer_info->line++;
|
||||||
lexer_info->column = 1;
|
lexer_info->column = 1;
|
||||||
|
|
@ -110,14 +110,14 @@ static char advance(LexerInfo *lexer_info) {
|
||||||
lexer_info->column++;
|
lexer_info->column++;
|
||||||
}
|
}
|
||||||
// Advance to and return the next character
|
// Advance to and return the next character
|
||||||
return lexer_info->source_code[++lexer_info->pos];
|
return lexer_info->source_code.str[++lexer_info->pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult lexer_result(LexerInfo *lexer_info, Token token, size_t start, size_t start_line) {
|
static LexerResult lexer_result(LexerInfo *lexer_info, Token token, size_t start, size_t start_line) {
|
||||||
// Create a LexerTokenResult to store the results of lexing the current token
|
// Create a LexerTokenResult to store the results of lexing the current token
|
||||||
LexerTokenResult *result = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
|
LexerTokenResult *result = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Failed to allocate memory.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Failed to allocate memory."), 1}};
|
||||||
result->type = SLS_RESULT;
|
result->type = SLS_RESULT;
|
||||||
result->result = token;
|
result->result = token;
|
||||||
result->file_info = get_file_info(lexer_info, start, start_line);
|
result->file_info = get_file_info(lexer_info, start, start_line);
|
||||||
|
|
@ -125,11 +125,11 @@ static LexerResult lexer_result(LexerInfo *lexer_info, Token token, size_t start
|
||||||
return (LexerResult){SLS_RESULT, .result = result};
|
return (LexerResult){SLS_RESULT, .result = result};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult lexer_error(LexerInfo *lexer_info, const char* message, size_t start, size_t start_line) {
|
static LexerResult lexer_error(LexerInfo *lexer_info, SlsStr message, size_t start, size_t start_line) {
|
||||||
// Create a LexerTokenResult to store an error from lexing the current token
|
// Create a LexerTokenResult to store an error from lexing the current token
|
||||||
LexerTokenResult *result = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
|
LexerTokenResult *result = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Failed to allocate memory.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Failed to allocate memory."), 1}};
|
||||||
result->type = SLS_ERROR;
|
result->type = SLS_ERROR;
|
||||||
result->error.message = message;
|
result->error.message = message;
|
||||||
result->error.code = 1;
|
result->error.code = 1;
|
||||||
|
|
@ -263,32 +263,32 @@ static LexerResult read_numeric(LexerInfo *lexer_info, char c, size_t start, siz
|
||||||
|
|
||||||
static LexerResult parse_character_literal(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
static LexerResult parse_character_literal(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
||||||
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Character Literals Not Implemented Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Character Literals Not Implemented Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult parse_string_literal(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
static LexerResult parse_string_literal(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
||||||
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: String Literals Not Implemented Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: String Literals Not Implemented Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult parse_token_string(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
static LexerResult parse_token_string(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
||||||
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Token Strings Not Implemented Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Token Strings Not Implemented Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult parse_array_literal(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
static LexerResult parse_array_literal(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
||||||
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Array Literals Not Implemented Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Array Literals Not Implemented Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult parse_type_tuples(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
static LexerResult parse_type_tuples(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
||||||
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Type Tuples Not Implemented Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Type Tuples Not Implemented Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult parse_identifiers_and_booleans(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
static LexerResult parse_identifiers_and_booleans(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
|
||||||
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
(void)lexer_info; (void)c; (void)start; (void)start_line;
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Identifiers and Booleans Not Implemented Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Identifiers and Booleans Not Implemented Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static LexerResult lexer_next(LexerInfo *lexer_info) {
|
static LexerResult lexer_next(LexerInfo *lexer_info) {
|
||||||
|
|
@ -322,9 +322,9 @@ static LexerResult lexer_next(LexerInfo *lexer_info) {
|
||||||
// Type Tuples
|
// Type Tuples
|
||||||
if (c == '(') return parse_type_tuples(lexer_info, c, start, start_line);
|
if (c == '(') return parse_type_tuples(lexer_info, c, start, start_line);
|
||||||
// Identifiers and Booleans
|
// Identifiers and Booleans
|
||||||
if (isascii(c)) return parse_identifiers_and_booleans(lexer_info, c, start, start_line);
|
if (sls_isascii(c)) return parse_identifiers_and_booleans(lexer_info, c, start, start_line);
|
||||||
// Lexing Error
|
// Lexing Error
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Unknown Character Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Unknown Character Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
void clean_token_result(LexerTokenResult *head) {
|
void clean_token_result(LexerTokenResult *head) {
|
||||||
|
|
@ -332,7 +332,10 @@ void clean_token_result(LexerTokenResult *head) {
|
||||||
LexerTokenResult *next;
|
LexerTokenResult *next;
|
||||||
while (head) {
|
while (head) {
|
||||||
next = head->next;
|
next = head->next;
|
||||||
if (head->type == SLS_ERROR) free(head->error.message);
|
if (head->type == SLS_ERROR) sls_str_free(&head->error.message);
|
||||||
|
else {
|
||||||
|
if (head->result.type == TOKEN_STRING) sls_str_free(&head->error.message);
|
||||||
|
}
|
||||||
if (head) free(head);
|
if (head) free(head);
|
||||||
head = next;
|
head = next;
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +377,7 @@ LexerResult lexical_analysis(LexerInfo *lexer_info) {
|
||||||
// Current should not be null_ptr
|
// Current should not be null_ptr
|
||||||
if (current == 0) {
|
if (current == 0) {
|
||||||
clean_token_result(head);
|
clean_token_result(head);
|
||||||
return (LexerResult){SLS_ERROR, .error = (SlsError){"Unknown Error.", 1}};
|
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Unknown Error."), 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (current->type != SLS_ERROR && current->result.type != TOKEN_EOF);
|
} while (current->type != SLS_ERROR && current->result.type != TOKEN_EOF);
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,316 @@
|
||||||
// November 2025
|
// November 2025
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
int isascii(unsigned char c) {
|
#include "sls/string.h"
|
||||||
|
#include "sls/lexer.h"
|
||||||
|
|
||||||
|
int sls_isascii(unsigned char c) {
|
||||||
return c < 128;
|
return c < 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strnlen(const char *s, size_t maxlen) {
|
size_t sls_str_nlen(const char *s, size_t maxlen) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < maxlen; i++)
|
for (i = 0; i < maxlen; i++)
|
||||||
if (s[i] == '\0') break;
|
if (s[i] == '\0') break;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SlsStr sls_str_malloc(const char *s, size_t maxlen) {
|
||||||
|
size_t length = sls_str_nlen(s, maxlen);
|
||||||
|
char *new_str = (char *)malloc(sizeof(char) * (length + 1));
|
||||||
|
if (new_str == NULL) return SLS_STR_NULL;
|
||||||
|
memcpy(new_str, s, length);
|
||||||
|
new_str[length] = '\0';
|
||||||
|
return (SlsStr){length, new_str, TRUE};
|
||||||
|
}
|
||||||
|
|
||||||
|
SlsStr sls_str_new(size_t length) {
|
||||||
|
char *new_str = (char *)calloc(length + 1, sizeof(char));
|
||||||
|
if (new_str == NULL) return SLS_STR_NULL;
|
||||||
|
return (SlsStr){length, new_str, TRUE};
|
||||||
|
}
|
||||||
|
|
||||||
|
SlsStr sls_str_cpy(const SlsStr s) {
|
||||||
|
return sls_str_malloc(s.str, s.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t sls_str_cmp(const SlsStr a, const SlsStr b) {
|
||||||
|
int cmp = strncmp(a.str, b.str, (a.len < b.len) ? a.len : b.len);
|
||||||
|
if (cmp != 0) return cmp;
|
||||||
|
return (a.len > b.len) - (a.len < b.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sls_str_free(SlsStr *s) {
|
||||||
|
if (s->allocated) {
|
||||||
|
free((void *)s->str);
|
||||||
|
s->len = 0;
|
||||||
|
s->str = NULL;
|
||||||
|
s->allocated = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FORMAT_PERCENT_ESCAPE,
|
||||||
|
FORMAT_C_STRINGS,
|
||||||
|
FORMAT_CHARACTER,
|
||||||
|
FORMAT_INTEGER_32,
|
||||||
|
FORMAT_INTEGER_64,
|
||||||
|
FORMAT_UNSIGNED_INTEGER_64,
|
||||||
|
FORMAT_SIZE_INTEGER,
|
||||||
|
FORMAT_FLOAT,
|
||||||
|
FORMAT_SLS_STR,
|
||||||
|
FORMAT_SLS_TOKEN_TYPE,
|
||||||
|
FORMAT_SLS_ARRAY_TYPE,
|
||||||
|
FORMAT_SLS_BUILTIN_INTEGER,
|
||||||
|
FORMAT_SLS_ERROR,
|
||||||
|
FORMAT_SLS_BOOLEAN,
|
||||||
|
} FormatStringTypes;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FormatStringTypes type;
|
||||||
|
union {
|
||||||
|
const char *c_string;
|
||||||
|
char character;
|
||||||
|
int32_t integer_32;
|
||||||
|
int64_t integer_64;
|
||||||
|
uint64_t unsigned_integer_64;
|
||||||
|
size_t size_integer;
|
||||||
|
double ffloat;
|
||||||
|
SlsStr sls_str;
|
||||||
|
TokenType token_type;
|
||||||
|
ArrayType array_type;
|
||||||
|
IntegerBuiltInType builtin_integer;
|
||||||
|
SlsError error;
|
||||||
|
Boolean boolean;
|
||||||
|
};
|
||||||
|
ptrdiff_t str_index;
|
||||||
|
size_t self_length;
|
||||||
|
} FormatStringItem;
|
||||||
|
|
||||||
|
static size_t number_length(int64_t i) {
|
||||||
|
if (i == 0) return 1;
|
||||||
|
size_t len = (i < 0 ? 1 : 0);
|
||||||
|
while (i) { len++; i /= 10; }
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t unsigned_number_length(uint64_t i) {
|
||||||
|
if (i == 0) return 1;
|
||||||
|
size_t len = 0;
|
||||||
|
while (i) { len++; i /= 10; }
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlsStr sls_format(const SlsStr s, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, s);
|
||||||
|
size_t count = 0;
|
||||||
|
const char *current = strchr(s.str, '%');
|
||||||
|
do {
|
||||||
|
if (!current) break;
|
||||||
|
if (!current[1]) break;
|
||||||
|
switch (current[1]) {
|
||||||
|
case '%':
|
||||||
|
case 'y':
|
||||||
|
case 'c':
|
||||||
|
case 'd':
|
||||||
|
case 'l':
|
||||||
|
case 'u':
|
||||||
|
case 'z':
|
||||||
|
case 'f':
|
||||||
|
case 's':
|
||||||
|
case 't':
|
||||||
|
case 'a':
|
||||||
|
case 'i':
|
||||||
|
case 'e':
|
||||||
|
case 'b':
|
||||||
|
count++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = strchr(current + 2, '%');
|
||||||
|
} while (current);
|
||||||
|
|
||||||
|
FormatStringItem *items = (FormatStringItem *)malloc(sizeof(FormatStringItem) * count);
|
||||||
|
if (items == NULL) return SLS_STR_NULL;
|
||||||
|
size_t i = 0;
|
||||||
|
const char *last_index = s.str;
|
||||||
|
size_t length = s.len;
|
||||||
|
current = strchr(s.str, '%');
|
||||||
|
do {
|
||||||
|
switch (current[1]) {
|
||||||
|
case '%':
|
||||||
|
items[i].type = FORMAT_PERCENT_ESCAPE;
|
||||||
|
length += items[i].self_length = 1;
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
items[i].type = FORMAT_C_STRINGS;
|
||||||
|
items[i].c_string = va_arg(args, const char *);
|
||||||
|
length += items[i].self_length = strlen(items[i].c_string);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
items[i].type = FORMAT_CHARACTER;
|
||||||
|
items[i].character = va_arg(args, int);
|
||||||
|
length += items[i].self_length = 1;
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
items[i].type = FORMAT_INTEGER_32;
|
||||||
|
items[i].integer_32 = va_arg(args, int32_t);
|
||||||
|
length += items[i].self_length = number_length(items[i].integer_32);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
items[i].type = FORMAT_INTEGER_64;
|
||||||
|
items[i].integer_64 = va_arg(args, int64_t);
|
||||||
|
length += items[i].self_length = number_length(items[i].integer_64);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
items[i].type = FORMAT_UNSIGNED_INTEGER_64;
|
||||||
|
items[i].unsigned_integer_64 = va_arg(args, uint64_t);
|
||||||
|
length += items[i].self_length = unsigned_number_length(items[i].unsigned_integer_64);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
items[i].type = FORMAT_SIZE_INTEGER;
|
||||||
|
items[i].size_integer = va_arg(args, size_t);
|
||||||
|
length += items[i].self_length = unsigned_number_length(items[i].size_integer);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
items[i].type = FORMAT_FLOAT;
|
||||||
|
items[i].ffloat = va_arg(args, double);
|
||||||
|
length += items[i].self_length = snprintf(NULL, 0, "%.2f", items[i].ffloat);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
items[i].type = FORMAT_SLS_STR;
|
||||||
|
items[i].sls_str = va_arg(args, SlsStr);
|
||||||
|
length += items[i].self_length = items[i].sls_str.len;
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
items[i].type = FORMAT_SLS_TOKEN_TYPE;
|
||||||
|
items[i].token_type = va_arg(args, TokenType);
|
||||||
|
length += items[i].self_length = sls_str_nlen(TOKEN_TYPES_NAMES[items[i].token_type], TYPE_NAMES_SAFE_LENGTH);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
items[i].type = FORMAT_SLS_ARRAY_TYPE;
|
||||||
|
items[i].array_type = va_arg(args, ArrayType);
|
||||||
|
length += items[i].self_length = sls_str_nlen(ARRAY_TYPES_NAMES[items[i].array_type], TYPE_NAMES_SAFE_LENGTH);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
items[i].type = FORMAT_SLS_BUILTIN_INTEGER;
|
||||||
|
items[i].builtin_integer = va_arg(args, IntegerBuiltInType);
|
||||||
|
length += items[i].self_length = sls_str_nlen(INTEGER_TYPES_NAMES[items[i].builtin_integer], TYPE_NAMES_SAFE_LENGTH);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
items[i].type = FORMAT_SLS_ERROR;
|
||||||
|
items[i].error = va_arg(args, SlsError);
|
||||||
|
length += items[i].self_length = items[i].error.message.len;
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
items[i].type = FORMAT_SLS_BOOLEAN;
|
||||||
|
items[i].boolean = va_arg(args, Boolean);
|
||||||
|
length += items[i].self_length = (items[i].boolean ? 4 : 5);
|
||||||
|
length -= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
items[i].str_index = (ptrdiff_t)(current - last_index);
|
||||||
|
last_index = current + 2;
|
||||||
|
i++;
|
||||||
|
current = strchr(current + 2, '%');
|
||||||
|
} while (current);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
char *temp = (char *)malloc(sizeof(char) * length);
|
||||||
|
if (temp == NULL) {
|
||||||
|
free(items);
|
||||||
|
return SLS_STR_NULL;
|
||||||
|
}
|
||||||
|
SlsStr str_new = sls_str_new(length);
|
||||||
|
if (str_new.str == NULL) {
|
||||||
|
free(items);
|
||||||
|
free(temp);
|
||||||
|
return SLS_STR_NULL;
|
||||||
|
}
|
||||||
|
char *str = (char *)str_new.str;
|
||||||
|
size_t item_i = 0;
|
||||||
|
ptrdiff_t target_i = 0;
|
||||||
|
ptrdiff_t source_i = 0;
|
||||||
|
|
||||||
|
while (item_i < count) {
|
||||||
|
memcpy(str + target_i, s.str + source_i, items[item_i].str_index);
|
||||||
|
target_i += items[item_i].str_index;
|
||||||
|
source_i += items[item_i].str_index + 2;
|
||||||
|
|
||||||
|
switch (items[item_i].type) {
|
||||||
|
case FORMAT_PERCENT_ESCAPE:
|
||||||
|
memcpy(temp, "%", items[item_i].self_length + 1);
|
||||||
|
break;
|
||||||
|
case FORMAT_C_STRINGS:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].c_string);
|
||||||
|
break;
|
||||||
|
case FORMAT_CHARACTER:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%c", items[item_i].character);
|
||||||
|
break;
|
||||||
|
case FORMAT_INTEGER_32:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%d", items[item_i].integer_32);
|
||||||
|
break;
|
||||||
|
case FORMAT_INTEGER_64:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%ld", items[item_i].integer_64);
|
||||||
|
break;
|
||||||
|
case FORMAT_UNSIGNED_INTEGER_64:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%lu", items[item_i].unsigned_integer_64);
|
||||||
|
break;
|
||||||
|
case FORMAT_SIZE_INTEGER:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%zu", items[item_i].size_integer);
|
||||||
|
break;
|
||||||
|
case FORMAT_FLOAT:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%.2f", items[item_i].ffloat); // Fixed-point decimal display
|
||||||
|
break;
|
||||||
|
case FORMAT_SLS_STR:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].sls_str.str);
|
||||||
|
break;
|
||||||
|
case FORMAT_SLS_TOKEN_TYPE:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%s", TOKEN_TYPES_NAMES[items[item_i].token_type]);
|
||||||
|
break;
|
||||||
|
case FORMAT_SLS_ARRAY_TYPE:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%s", ARRAY_TYPES_NAMES[items[item_i].array_type]);
|
||||||
|
break;
|
||||||
|
case FORMAT_SLS_BUILTIN_INTEGER:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%s", INTEGER_TYPES_NAMES[items[item_i].builtin_integer]);
|
||||||
|
break;
|
||||||
|
case FORMAT_SLS_ERROR:
|
||||||
|
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].error.message.str);
|
||||||
|
break;
|
||||||
|
case FORMAT_SLS_BOOLEAN:
|
||||||
|
memcpy(temp, (items[item_i].boolean ? "TRUE" : "FALSE"), items[item_i].self_length + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(str + target_i, temp, items[item_i].self_length);
|
||||||
|
target_i += items[item_i].self_length;
|
||||||
|
item_i++;
|
||||||
|
}
|
||||||
|
if (s.len > source_i)
|
||||||
|
memcpy(str + target_i, s.str + source_i, s.len - source_i);
|
||||||
|
str[str_new.len] = '\0';
|
||||||
|
|
||||||
|
free(items);
|
||||||
|
free(temp);
|
||||||
|
return str_new;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@
|
||||||
#include "tests/lexer_test_helpers.h"
|
#include "tests/lexer_test_helpers.h"
|
||||||
#include "tests/tests.h"
|
#include "tests/tests.h"
|
||||||
|
|
||||||
static const double FLOAT_TEST_PRECISION = 0.01;
|
static const double FLOAT_TEST_PRECISION = 0.0078125;
|
||||||
|
|
||||||
// Test start and end helpers
|
// Test start and end helpers
|
||||||
|
|
||||||
LexerTest start_up_test(const char *test_name, const char *test_code) {
|
LexerTest start_up_test(SlsStr test_name, SlsStr 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 } };
|
||||||
|
|
@ -33,45 +33,63 @@ void clean_up_test(LexerResult result) {
|
||||||
clean_token_result(result.result);
|
clean_token_result(result.result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult error_test(LexerTest *test, LexerResult result, SlsError error) {
|
TestResult error_test_out_of_mem(LexerTest *test) {
|
||||||
test->result.status = TEST_ERROR;
|
test->result.status = TEST_ERROR;
|
||||||
test->result.error = error;
|
test->result.error = (SlsError){SLS_STR("Out Of Memory Error."), 1};
|
||||||
clean_up_test(result);
|
|
||||||
return test->result;
|
return test->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message) {
|
TestResult error_test(LexerTest *test, LexerResult result, SlsError error) {
|
||||||
if (message == 0) return error_test(test, result, (SlsError) {
|
clean_up_test(result);
|
||||||
.message = "Out of Memory Error!", .code = 1, });
|
|
||||||
|
if (error.message.str == NULL) return error_test_out_of_mem(test);
|
||||||
|
|
||||||
|
test->result.status = TEST_ERROR;
|
||||||
|
test->result.error = error;
|
||||||
|
test->result.error.message = sls_str_cpy(error.message);
|
||||||
|
|
||||||
|
if (test->result.error.message.str == NULL) return error_test_out_of_mem(test);
|
||||||
|
return test->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult logic_fail_test(LexerTest *test, LexerResult result, SlsStr message) {
|
||||||
|
clean_up_test(result);
|
||||||
|
|
||||||
test->result.status = TEST_LOGIC_FAIL;
|
test->result.status = TEST_LOGIC_FAIL;
|
||||||
test->result.message = message;
|
test->result.message = message;
|
||||||
clean_up_test(result);
|
|
||||||
return test->result;
|
return test->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult logic_error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
|
TestResult logic_error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
|
||||||
|
clean_up_test(result);
|
||||||
|
|
||||||
|
if (error.message.str == NULL) return error_test_out_of_mem(test);
|
||||||
|
|
||||||
test->result.status = TEST_LOGIC_ERROR_FAIL;
|
test->result.status = TEST_LOGIC_ERROR_FAIL;
|
||||||
test->result.error = error;
|
test->result.error = error;
|
||||||
|
test->result.error.message = sls_str_cpy(error.message);
|
||||||
|
|
||||||
size_t message_length = strlen(error.message) + 1;
|
if (test->result.error.message.str == NULL) return error_test_out_of_mem(test);
|
||||||
const char *message = (char *)malloc(sizeof(char) * message_length);
|
|
||||||
strncpy(message, error.message, message_length);
|
|
||||||
test->result.error.message = message;
|
|
||||||
|
|
||||||
clean_up_test(result);
|
|
||||||
return test->result;
|
return test->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
|
TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
|
||||||
|
clean_up_test(result);
|
||||||
|
|
||||||
|
if (error.message.str == NULL) return error_test_out_of_mem(test);
|
||||||
|
|
||||||
test->result.status = TEST_ERROR_FAIL;
|
test->result.status = TEST_ERROR_FAIL;
|
||||||
test->result.error = error;
|
test->result.error = error;
|
||||||
clean_up_test(result);
|
test->result.error.message = sls_str_cpy(error.message);
|
||||||
|
|
||||||
|
if (test->result.error.message.str == NULL) return error_test_out_of_mem(test);
|
||||||
return test->result;
|
return test->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult skip_test(LexerTest *test, LexerResult result) {
|
TestResult skip_test(LexerTest *test, LexerResult result) {
|
||||||
test->result.status = TEST_NOT_IMPLEMENTED;
|
|
||||||
clean_up_test(result);
|
clean_up_test(result);
|
||||||
|
|
||||||
|
test->result.status = TEST_NOT_IMPLEMENTED;
|
||||||
return test->result;
|
return test->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,198 +99,107 @@ TestResult skip_test_no_result(LexerTest *test) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult pass_test(LexerTest *test, LexerResult result) {
|
TestResult pass_test(LexerTest *test, LexerResult result) {
|
||||||
test->result.status = TEST_PASS;
|
|
||||||
clean_up_test(result);
|
clean_up_test(result);
|
||||||
|
|
||||||
|
test->result.status = TEST_PASS;
|
||||||
return test->result;
|
return test->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test messages
|
// Test messages
|
||||||
|
|
||||||
static char *unexpected_end_of_token_stream(size_t i) {
|
static SlsStr unexpected_end_of_token_stream(size_t i) {
|
||||||
size_t length = ceil(log10(i)) + 47;
|
return sls_format(SLS_STR("Unexpected end of token stream (%z tokens found)"), i - 1);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Unexpected end of token stream (%zu tokens found)", i - 1);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *expected_end_of_token_stream(size_t i) {
|
static SlsStr expected_end_of_token_stream(size_t i) {
|
||||||
size_t length = ceil(log10(i)) + 47;
|
return sls_format(SLS_STR("Expected end of token stream (more than %z tokens found)"), i - 1);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Expected end of token stream (more than %zu tokens found)", i - 1);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *token_should_be(size_t i, TokenType should, TokenType found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z should be a %t, but found a %t"), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu should be a %s, but found a %s", i, TOKEN_TYPES_NAMES[should], TOKEN_TYPES_NAMES[found]);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *integer_type_should_be(size_t i, IntegerBuiltInType should, IntegerBuiltInType found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z integer type should be a %i, but found a %i"), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *integer_value_should_be(size_t i, uint64_t should, uint64_t found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z integer value should be %i, but found %i"), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu integer value should be %lu, but found %lu", i, should, found);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *float_value_should_be(size_t i, double should, double found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z float value should be %f, but found %f"), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu float value should be %.2f, but found %.2f", i, should, found);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *identifier_should_be_literal(size_t i) {
|
static SlsStr identifier_should_be_literal(size_t i) {
|
||||||
size_t length = ceil(log10(i + 1)) + 51;
|
return sls_format(SLS_STR("Token #%z identifier should be an identifier literal"), i);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu identifier should be an identifier literal", i);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *identifier_should_not_be_literal(size_t i) {
|
static SlsStr identifier_should_not_be_literal(size_t i) {
|
||||||
size_t length = ceil(log10(i + 1)) + 55;
|
return sls_format(SLS_STR("Token #%z identifier should not be an identifier literal"), i);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu identifier should not be an identifier literal", i);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *token_length_should_be(size_t i, TokenType type, uint64_t should, uint64_t found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z of type %t length should be %u, but found %u"), i, type, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu of type %s length should be %lu, but found %lu", i, TOKEN_TYPES_NAMES[type], should, found);
|
|
||||||
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 SlsStr token_value_string_should_be(size_t i, TokenType type, SlsStr should, SlsStr 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;
|
return sls_format(SLS_STR("Token #%z of type %t string value should be %s, but found %s"), i, type, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *boolean_should_be(size_t i, Boolean value) {
|
static SlsStr boolean_should_be(size_t i, Boolean value) {
|
||||||
size_t length = ceil(log10(i + 1)) + 45;
|
if (value) return sls_format(SLS_STR("Token #%z boolean should be true, but is false"), i);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
else return sls_format(SLS_STR("Token #%z boolean should be false, but is true"), i);
|
||||||
if (string == 0) return string;
|
|
||||||
if (value) snprintf(string, length, "Token #%zu boolean should be true, but is false", i);
|
|
||||||
else snprintf(string, length, "Token #%zu boolean should be false, but is true", i);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *array_type_should_be(size_t i, ArrayType should, ArrayType found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z should be a %a, but found a %a"), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu should be a %s, but found a %s", i, ARRAY_TYPES_NAMES[should], ARRAY_TYPES_NAMES[found]);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *array_dimensions_should_be(size_t i, size_t should, size_t found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z array dimensions should be %z, but found %z"), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu array dimensions should be %zu, but found %zu", i, should, found);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *array_element_shape_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) {
|
static SlsStr array_dimension_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;
|
return sls_format(SLS_STR("Token #%z dimension %z of array type %a should be shape %u, but found %u"), i, j, type, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *array_element_integer_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z element %z of array type %a should be %u, but found %u"), i, j, type, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *array_element_float_should_be(size_t i, size_t j, ArrayType type, double should, double found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z element %z of array type %a should be %f, but found %f"), i, j, type, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 SlsStr array_element_string_should_be(size_t i, size_t j, ArrayType type, SlsStr should, SlsStr 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;
|
return sls_format(SLS_STR("Token #%z element %z of array type %a should be %s, but found %s"), i, j, type, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *array_element_boolean_should_be(size_t i, size_t j, ArrayType type, Boolean value) {
|
static SlsStr 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;
|
if (value) return sls_format(SLS_STR("Token #%z element %z of array type %a should be true, but is false"), i, j, type);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
else return sls_format(SLS_STR("Token #%z element %z of array type %a should be false, but is true"), i, j, type);
|
||||||
if (string == 0) return string;
|
|
||||||
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 #%zu element %zu of array type %s should be false, but found true", i, j, TOKEN_TYPES_NAMES[type]);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *type_tuple_element_integer_should_be(size_t i, size_t j, uint64_t should, uint64_t found) {
|
static SlsStr 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;
|
return sls_format(SLS_STR("Token #%z element %u of type tuple should be %u, but found %u"), i, j, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu element %zu of type tuple should be %lu, but found %lu", i, j, should, found);
|
|
||||||
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 SlsStr type_tuple_element_string_should_be(size_t i, size_t j, SlsStr should, SlsStr found) {
|
||||||
size_t length = ceil(log10(i + 1)) + ceil(log10(j + 1)) + strnlen(should, value_length) + strnlen(found, value_length) + 54;
|
return sls_format(SLS_STR("Token #%z element %z of type tuple should be %s, but found %s"), i, j, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu element %zu of type tuple should be %s, but found %s", i, j, should, found);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *type_tuple_element_boolean_should_be(size_t i, size_t j, Boolean value) {
|
static SlsStr 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;
|
if (value) return sls_format(SLS_STR("Token #%z element %z of type tuple should be true, but is false"), i, j);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
else return sls_format(SLS_STR("Token #%z element %z of type tuple should be false, but is true"), i, j);
|
||||||
if (string == 0) return string;
|
|
||||||
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 #%zu element %zu of type tuple should be false, but found true", i, j);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *token_should_be_error(size_t i, TestErrorMessage should, TokenType found) {
|
static SlsStr token_should_be_error(size_t i, SlsStr should, TokenType found) {
|
||||||
size_t length = ceil(log10(i + 1)) + should.length + strnlen(TOKEN_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 72;
|
return sls_format(SLS_STR("Token #%z should be an error with a message of \"%s\", but found token of type %t"), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu should be an error with a message of %s, but found token of type %s", i, should.message, TOKEN_TYPES_NAMES[found]);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *error_should_be(size_t i, TestErrorMessage should, SlsError found) {
|
static SlsStr error_should_be(size_t i, SlsStr should, SlsError found) {
|
||||||
size_t length = ceil(log10(i + 1)) + should.length + strlen(found.message) + 77;
|
return sls_format(SLS_STR("Token #%z should be an error with a message of \"%s\", but found error with message \"%e\""), i, should, found);
|
||||||
char *string = (char *)malloc(sizeof(char) * length);
|
|
||||||
if (string == 0) return string;
|
|
||||||
snprintf(string, length, "Token #%zu should be an error with a message of %s, but found error with message %s", i, should.message, found.message);
|
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test parts
|
// Test parts
|
||||||
|
|
@ -305,7 +232,7 @@ static Boolean test_array_type(LexerTest *test, LexerResult result, size_t i, Ar
|
||||||
}
|
}
|
||||||
for (size_t 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_dimension_shape_should_be(i + 1, j, array_type, shape[j], head->result.array_literal.shape[j]));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -333,11 +260,11 @@ Boolean test_identifier_value(LexerTest *test, LexerResult result, size_t i, Tes
|
||||||
} if (head->result.identifier.is_literal != value->is_literal) {
|
} if (head->result.identifier.is_literal != value->is_literal) {
|
||||||
logic_fail_test(test, result, value->is_literal ? identifier_should_be_literal(i + 1) : identifier_should_not_be_literal(i + 1));
|
logic_fail_test(test, result, value->is_literal ? identifier_should_be_literal(i + 1) : identifier_should_not_be_literal(i + 1));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (head->result.identifier.length == strnlen(value->name, value->length)) {
|
} if (head->result.identifier.name.len == value->name.len) {
|
||||||
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->name, value->length), head->result.identifier.length));
|
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, value->name.len, head->result.identifier.name.len));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (strncmp(head->result.identifier.name, value->name, value->length) != 0) {
|
} if (sls_str_cmp(head->result.identifier.name, value->name) != 0) {
|
||||||
logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, strnlen(value->name, value->length), head->result.identifier.name, value->name));
|
logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, head->result.identifier.name, value->name));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
@ -382,16 +309,16 @@ Boolean test_double_value(LexerTest *test, LexerResult result, size_t i, double
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean test_string_value(LexerTest *test, LexerResult result, size_t i, TestStringValue *value) {
|
Boolean test_string_value(LexerTest *test, LexerResult result, size_t i, SlsStr value) {
|
||||||
static const TokenType token_type = TOKEN_STRING;
|
static const TokenType token_type = TOKEN_STRING;
|
||||||
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)) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (head->result.string_literal.length == strnlen(value->string, value->length)) {
|
} if (head->result.string_literal.len == value.len) {
|
||||||
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->string, value->length), head->result.string_literal.length));
|
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, value.len, head->result.string_literal.len));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (strncmp(head->result.string_literal.value, value->string, value->length) != 0) {
|
} if (sls_str_cmp(head->result.string_literal, value) != 0) {
|
||||||
logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, fmax(strnlen(value->string, value->length), strnlen(head->result.string_literal.value, value->length)), value->string, head->result.string_literal.value));
|
logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, value, head->result.string_literal));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
@ -418,11 +345,11 @@ Boolean test_array_identifier_value(LexerTest *test, LexerResult result, size_t
|
||||||
size_t length = 1;
|
size_t length = 1;
|
||||||
for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
|
for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
|
||||||
for (size_t 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].name.len == values->values[j].name.len) {
|
||||||
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].name.len, head->result.array_literal.identifiers[j].name.len));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (strncmp(head->result.array_literal.identifiers[j].name, values->values[j].name, values->values[j].length)) {
|
} if (sls_str_cmp(head->result.array_literal.identifiers[j].name, values->values[j].name)) {
|
||||||
logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j].length, values->values[j].name, head->result.array_literal.identifiers[j].name));
|
logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j].name, head->result.array_literal.identifiers[j].name));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (head->result.array_literal.identifiers[j].is_literal) {
|
} if (head->result.array_literal.identifiers[j].is_literal) {
|
||||||
logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, TRUE));
|
logic_fail_test(test, result, array_element_boolean_should_be(i + 1, j, array_type, TRUE));
|
||||||
|
|
@ -492,11 +419,11 @@ Boolean test_array_string_value(LexerTest *test, LexerResult result, size_t i, T
|
||||||
size_t length = 1;
|
size_t length = 1;
|
||||||
for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
|
for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
|
||||||
for (size_t 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].len == values->values[j].len) {
|
||||||
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].len, head->result.array_literal.string_literals[j].len));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (strncmp(head->result.array_literal.string_literals[j].value, values->values[j].string, values->values[j].length)) {
|
} if (sls_str_cmp(head->result.array_literal.string_literals[j], values->values[j])) {
|
||||||
logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j].length, values->values[j].string, head->result.array_literal.string_literals[j].value));
|
logic_fail_test(test, result, array_element_string_should_be(i + 1, j, array_type, values->values[j], head->result.array_literal.string_literals[j]));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -525,8 +452,8 @@ Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size
|
||||||
LexerTokenResult *head = get_token(result.result, i);
|
LexerTokenResult *head = get_token(result.result, i);
|
||||||
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 (sls_str_cmp(head->result.array_literal.struct_inline.name, values->struct_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));
|
logic_fail_test(test, result, token_value_string_should_be(i + 1, TOKEN_IDENTIFIER, values->struct_name, head->result.array_literal.struct_inline.name));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
size_t length = 1;
|
size_t length = 1;
|
||||||
|
|
@ -582,22 +509,22 @@ Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, Tes
|
||||||
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 (size_t 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].name.len == values->input_values[j].name.len) {
|
||||||
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].name.len, head->result.type_tuple.input_identifiers[j].name.len));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (strncmp(head->result.type_tuple.input_identifiers[j].name, values->input_values[j].name, values->input_values[j].length)) {
|
} if (sls_str_cmp(head->result.type_tuple.input_identifiers[j].name, values->input_values[j].name)) {
|
||||||
logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->input_values[j].length, values->input_values[j].name, head->result.type_tuple.input_identifiers[j].name));
|
logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->input_values[j].name, head->result.type_tuple.input_identifiers[j].name));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (head->result.type_tuple.input_identifiers[j].is_literal) {
|
} if (head->result.type_tuple.input_identifiers[j].is_literal) {
|
||||||
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 (size_t 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].name.len == values->output_values[j].name.len) {
|
||||||
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].name.len, head->result.type_tuple.output_identifiers[j].name.len));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (strncmp(head->result.type_tuple.output_identifiers[j].name, values->output_values[j].name, values->input_values[j].length)) {
|
} if (sls_str_cmp(head->result.type_tuple.output_identifiers[j].name, values->output_values[j].name)) {
|
||||||
logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->output_values[j].length, values->output_values[j].name, head->result.type_tuple.output_identifiers[j].name));
|
logic_fail_test(test, result, type_tuple_element_string_should_be(i + 1, j, values->output_values[j].name, head->result.type_tuple.output_identifiers[j].name));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (head->result.type_tuple.output_identifiers[j].is_literal) {
|
} if (head->result.type_tuple.output_identifiers[j].is_literal) {
|
||||||
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));
|
||||||
|
|
@ -607,13 +534,13 @@ Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, Tes
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean test_for_error(LexerTest *test, LexerResult result, size_t i, TestErrorMessage *error) {
|
Boolean test_for_error(LexerTest *test, LexerResult result, size_t i, SlsStr error) {
|
||||||
LexerTokenResult *head = get_token(result.result, i);
|
LexerTokenResult *head = get_token(result.result, i);
|
||||||
if (head->type != SLS_ERROR) {
|
if (head->type != SLS_ERROR) {
|
||||||
logic_fail_test(test, result, token_should_be_error(i + 1, *error, head->result.type));
|
logic_fail_test(test, result, token_should_be_error(i + 1, error, head->result.type));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (strncmp(head->error.message, error->message, error->length+1) != 0) {
|
} if (sls_str_cmp(head->error.message, error) != 0) {
|
||||||
logic_fail_test(test, result, error_should_be(i + 1, *error, head->error));
|
logic_fail_test(test, result, error_should_be(i + 1, error, head->error));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,224 @@
|
||||||
|
// Kyler Olsen
|
||||||
|
// YREA SLS
|
||||||
|
// String Tests
|
||||||
|
// November 2025
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "sls/string.h"
|
||||||
|
#include "sls/lexer.h"
|
||||||
|
#include "sls/errors.h"
|
||||||
|
#include "tests/tests.h"
|
||||||
|
|
||||||
|
static const size_t NUM_STRING_TESTS = 10;
|
||||||
|
|
||||||
|
static TestResult pass_string_test(SlsStr test_name) {
|
||||||
|
TestResult result = {.name = test_name, .status = TEST_NOT_IMPLEMENTED};
|
||||||
|
result.status = TEST_PASS;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestResult fail_string_test(SlsStr test_name, SlsStr message) {
|
||||||
|
TestResult result = { .name = test_name, .status = TEST_NOT_IMPLEMENTED };
|
||||||
|
result.status = TEST_ERROR;
|
||||||
|
result.message = sls_str_cpy(message);
|
||||||
|
|
||||||
|
if (result.message.str == NULL) {
|
||||||
|
result.error = (SlsError){ SLS_STR("Out Of Memory Error."), 1 };
|
||||||
|
result.status = TEST_ERROR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sls_str_malloc and sls_str_cpy
|
||||||
|
static TestResult test_malloc_and_copy() {
|
||||||
|
const char* original = "Hello, SLS!";
|
||||||
|
SlsStr s = sls_str_malloc(original, strlen(original));
|
||||||
|
if (!s.str) return fail_string_test(SLS_STR("test_malloc_and_copy"), SLS_STR("Allocation failed"));
|
||||||
|
|
||||||
|
if (strcmp(s.str, original) != 0) {
|
||||||
|
sls_str_free(&s);
|
||||||
|
return fail_string_test(SLS_STR("test_malloc_and_copy"), SLS_STR("Copied string mismatch"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SlsStr copy = sls_str_cpy(s);
|
||||||
|
if (!copy.str || strcmp(copy.str, original) != 0) {
|
||||||
|
sls_str_free(&s);
|
||||||
|
sls_str_free(©);
|
||||||
|
return fail_string_test(SLS_STR("test_malloc_and_copy"), SLS_STR("sls_str_cpy failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sls_str_free(&s);
|
||||||
|
sls_str_free(©);
|
||||||
|
return pass_string_test(SLS_STR("test_malloc_and_copy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sls_str_cmp
|
||||||
|
static TestResult test_compare_strings() {
|
||||||
|
SlsStr a = sls_str_malloc("abc", 3);
|
||||||
|
SlsStr b = sls_str_malloc("abc", 3);
|
||||||
|
SlsStr c = sls_str_malloc("abd", 3);
|
||||||
|
|
||||||
|
if (sls_str_cmp(a, b) != 0) goto fail;
|
||||||
|
if (sls_str_cmp(a, c) >= 0) goto fail;
|
||||||
|
if (sls_str_cmp(c, a) <= 0) goto fail;
|
||||||
|
|
||||||
|
sls_str_free(&a);
|
||||||
|
sls_str_free(&b);
|
||||||
|
sls_str_free(&c);
|
||||||
|
return pass_string_test(SLS_STR("test_compare_strings"));
|
||||||
|
|
||||||
|
fail:
|
||||||
|
sls_str_free(&a);
|
||||||
|
sls_str_free(&b);
|
||||||
|
sls_str_free(&c);
|
||||||
|
return fail_string_test(SLS_STR("test_compare_strings"), SLS_STR("Comparison test failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sls_format for basic placeholders
|
||||||
|
static TestResult test_format_basic_placeholders() {
|
||||||
|
SlsStr fmt = SLS_STR("Char: %c, Int: %d, Long: %l, Unsigned: %u, Size: %z, Float: %f, C-String: %y");
|
||||||
|
const char *s = "Test";
|
||||||
|
SlsStr result = sls_format(fmt, 'X', -42, (int64_t)1234567890123, (uint64_t)9876543210, (size_t)1024, 3.14, s);
|
||||||
|
|
||||||
|
if (!result.str) return fail_string_test(SLS_STR("test_format_basic_placeholders"), SLS_STR("Formatting returned NULL"));
|
||||||
|
|
||||||
|
const char* expected = "Char: X, Int: -42, Long: 1234567890123, Unsigned: 9876543210, Size: 1024, Float: 3.14, C-String: Test";
|
||||||
|
if (strcmp(result.str, expected) != 0) {
|
||||||
|
sls_str_free(&result);
|
||||||
|
return fail_string_test(SLS_STR("test_format_basic_placeholders"), SLS_STR("Formatted string mismatch"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sls_str_free(&result);
|
||||||
|
return pass_string_test(SLS_STR("test_format_basic_placeholders"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sls_format for SLS types: %s, %t, %a, %i, %e, %b
|
||||||
|
static TestResult test_format_sls_types() {
|
||||||
|
// Placeholder values
|
||||||
|
SlsStr sls_str_val = SLS_STR("SLS_STRING");
|
||||||
|
TokenType tok = 0; // Assuming TOKEN_TYPES_NAMES[0] exists
|
||||||
|
ArrayType arr = 0; // Assuming ARRAY_TYPES_NAMES[0] exists
|
||||||
|
IntegerBuiltInType ib = 0; // Assuming INTEGER_TYPES_NAMES[0] exists
|
||||||
|
SlsError err = {SLS_STR("ErrorMessage"), 1};
|
||||||
|
Boolean boolean_true = TRUE;
|
||||||
|
|
||||||
|
SlsStr fmt = SLS_STR("Str:%s Tok:%t Arr:%a IntType:%i Err:%e Bool:%b");
|
||||||
|
SlsStr result = sls_format(fmt, sls_str_val, tok, arr, ib, err, boolean_true);
|
||||||
|
|
||||||
|
if (!result.str) return fail_string_test(SLS_STR("test_format_sls_types"), SLS_STR("Formatting returned NULL"));
|
||||||
|
|
||||||
|
char expected[256];
|
||||||
|
snprintf(expected, 256, "Str:%s Tok:%s Arr:%s IntType:%s Err:%s Bool:TRUE",
|
||||||
|
sls_str_val.str,
|
||||||
|
TOKEN_TYPES_NAMES[tok],
|
||||||
|
ARRAY_TYPES_NAMES[arr],
|
||||||
|
INTEGER_TYPES_NAMES[ib],
|
||||||
|
err.message.str);
|
||||||
|
|
||||||
|
if (strcmp(result.str, expected) != 0) {
|
||||||
|
sls_str_free(&result);
|
||||||
|
return fail_string_test(SLS_STR("test_format_sls_types"), SLS_STR("Formatted string mismatch for SLS types"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sls_str_free(&result);
|
||||||
|
return pass_string_test(SLS_STR("test_format_sls_types"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sls_format with %% escape
|
||||||
|
static TestResult test_format_percent_escape() {
|
||||||
|
SlsStr fmt = SLS_STR("Progress: 100%% complete");
|
||||||
|
SlsStr result = sls_format(fmt);
|
||||||
|
|
||||||
|
if (!result.str) return fail_string_test(SLS_STR("test_format_percent_escape"), SLS_STR("Formatting returned NULL"));
|
||||||
|
if (strcmp(result.str, "Progress: 100% complete") != 0) {
|
||||||
|
sls_str_free(&result);
|
||||||
|
return fail_string_test(SLS_STR("test_format_percent_escape"), SLS_STR("Percent escape failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sls_str_free(&result);
|
||||||
|
return pass_string_test(SLS_STR("test_format_percent_escape"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sls_str_new allocation and zero-init
|
||||||
|
static TestResult test_new_string_allocation() {
|
||||||
|
SlsStr s = sls_str_new(10);
|
||||||
|
if (!s.str) return fail_string_test(SLS_STR("test_new_string_allocation"), SLS_STR("Allocation failed"));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < s.len; i++) {
|
||||||
|
if (s.str[i] != 0) {
|
||||||
|
sls_str_free(&s);
|
||||||
|
return fail_string_test(SLS_STR("test_new_string_allocation"), SLS_STR("Memory not zero-initialized"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sls_str_free(&s);
|
||||||
|
return pass_string_test(SLS_STR("test_new_string_allocation"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test empty string
|
||||||
|
static TestResult test_empty_string() {
|
||||||
|
SlsStr s = sls_str_malloc("", 0);
|
||||||
|
if (!s.str || s.len != 0) return fail_string_test(SLS_STR("test_empty_string"), SLS_STR("Empty string allocation failed"));
|
||||||
|
sls_str_free(&s);
|
||||||
|
return pass_string_test(SLS_STR("test_empty_string"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test long string
|
||||||
|
static TestResult test_long_string() {
|
||||||
|
size_t len = 1024;
|
||||||
|
char* long_str = malloc(len + 1);
|
||||||
|
for (size_t i = 0; i < len; i++) long_str[i] = 'A';
|
||||||
|
long_str[len] = '\0';
|
||||||
|
|
||||||
|
SlsStr s = sls_str_malloc(long_str, len);
|
||||||
|
if (!s.str || s.len != len) {
|
||||||
|
free(long_str);
|
||||||
|
return fail_string_test(SLS_STR("test_long_string"), SLS_STR("Long string allocation failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sls_str_free(&s);
|
||||||
|
free(long_str);
|
||||||
|
return pass_string_test(SLS_STR("test_long_string"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test NULL pointer handling in sls_str_free
|
||||||
|
static TestResult test_free_null() {
|
||||||
|
SlsStr s = SLS_STR_NULL;
|
||||||
|
sls_str_free(&s); // Should safely do nothing
|
||||||
|
return pass_string_test(SLS_STR("test_free_null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sls_str_nlen edge cases
|
||||||
|
static TestResult test_str_nlen_edge() {
|
||||||
|
const char* str = "ABCDE";
|
||||||
|
if (sls_str_nlen(str, 0) != 0) return fail_string_test(SLS_STR("test_str_nlen_edge"), SLS_STR("Maxlen=0 failed"));
|
||||||
|
if (sls_str_nlen(str, 3) != 3) return fail_string_test(SLS_STR("test_str_nlen_edge"), SLS_STR("Maxlen=3 failed"));
|
||||||
|
if (sls_str_nlen(str, 10) != 5) return fail_string_test(SLS_STR("test_str_nlen_edge"), SLS_STR("Maxlen>strlen failed"));
|
||||||
|
return pass_string_test(SLS_STR("test_str_nlen_edge"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run all string tests
|
||||||
|
TestsReport run_string_tests() {
|
||||||
|
TestsReport report = {
|
||||||
|
.section = SLS_STR("string_tests"),
|
||||||
|
.count = NUM_STRING_TESTS,
|
||||||
|
.tests = malloc(sizeof(TestResult) * NUM_STRING_TESTS)
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
report.tests[i++] = test_malloc_and_copy();
|
||||||
|
report.tests[i++] = test_compare_strings();
|
||||||
|
report.tests[i++] = test_format_basic_placeholders();
|
||||||
|
report.tests[i++] = test_format_sls_types();
|
||||||
|
report.tests[i++] = test_format_percent_escape();
|
||||||
|
report.tests[i++] = test_new_string_allocation();
|
||||||
|
report.tests[i++] = test_empty_string();
|
||||||
|
report.tests[i++] = test_long_string();
|
||||||
|
report.tests[i++] = test_free_null();
|
||||||
|
report.tests[i++] = test_str_nlen_edge();
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include "sls/errors.h"
|
#include "sls/errors.h"
|
||||||
#include "tests/tests.h"
|
#include "tests/tests.h"
|
||||||
|
|
||||||
const char *TEST_FILE_NAME = "TEST_FILE.SLS";
|
const SlsStr TEST_FILE_NAME = SLS_STR("TEST_FILE.SLS");
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t errored;
|
uint16_t errored;
|
||||||
|
|
@ -22,45 +22,45 @@ typedef struct {
|
||||||
uint16_t total;
|
uint16_t total;
|
||||||
} TestCounts;
|
} TestCounts;
|
||||||
|
|
||||||
static void lexer_test_report(TestsReport reports, TestCounts *counts) {
|
static void test_report(TestsReport reports, TestCounts *counts) {
|
||||||
counts->total += reports.count;
|
counts->total += reports.count;
|
||||||
for (size_t i = 0; i < reports.count; i++) {
|
for (size_t i = 0; i < reports.count; i++) {
|
||||||
switch (reports.tests[i].status) {
|
switch (reports.tests[i].status) {
|
||||||
case TEST_ERROR:
|
case TEST_ERROR:
|
||||||
// Bright Red
|
// Bright Red
|
||||||
printf("\x1b[91mTest errored: %s\n\t%s\n\x1b[0m", reports.tests[i].name, reports.tests[i].error.message);
|
printf("\x1b[91mTest errored: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].error.message.str);
|
||||||
counts->errored += 1;
|
counts->errored += 1;
|
||||||
break;
|
break;
|
||||||
case TEST_ERROR_FAIL:
|
case TEST_ERROR_FAIL:
|
||||||
// Magenta
|
// Magenta
|
||||||
printf("\x1b[35mLexing errored: %s\n\t%s\n\x1b[0m", reports.tests[i].name, reports.tests[i].error.message);
|
printf("\x1b[35mLexing errored: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].error.message.str);
|
||||||
counts->error_failed += 1;
|
counts->error_failed += 1;
|
||||||
break;
|
break;
|
||||||
case TEST_LOGIC_ERROR_FAIL:
|
case TEST_LOGIC_ERROR_FAIL:
|
||||||
// Red
|
// Red
|
||||||
printf("\x1b[31mTest failed with lexical error: %s\n\t%s\n\x1b[0m", reports.tests[i].name, reports.tests[i].error.message);
|
printf("\x1b[31mTest failed with lexical error: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].error.message.str);
|
||||||
counts->logic_error_failed += 1;
|
counts->logic_error_failed += 1;
|
||||||
free(reports.tests[i].message);
|
sls_str_free(&reports.tests[i].message);
|
||||||
break;
|
break;
|
||||||
case TEST_LOGIC_FAIL:
|
case TEST_LOGIC_FAIL:
|
||||||
// Red
|
// Red
|
||||||
printf("\x1b[31mTest failed: %s\n\t%s\n\x1b[0m", reports.tests[i].name, reports.tests[i].message);
|
printf("\x1b[31mTest failed: %s\n\t%s\n\x1b[0m", reports.tests[i].name.str, reports.tests[i].message.str);
|
||||||
counts->logic_failed += 1;
|
counts->logic_failed += 1;
|
||||||
free(reports.tests[i].message);
|
sls_str_free(&reports.tests[i].message);
|
||||||
break;
|
break;
|
||||||
case TEST_PASS:
|
case TEST_PASS:
|
||||||
// Green
|
// Green
|
||||||
printf("\x1b[32mTest passed: %s\n\x1b[0m", reports.tests[i].name);
|
printf("\x1b[32mTest passed: %s\n\x1b[0m", reports.tests[i].name.str);
|
||||||
counts->passed += 1;
|
counts->passed += 1;
|
||||||
break;
|
break;
|
||||||
case TEST_NOT_IMPLEMENTED:
|
case TEST_NOT_IMPLEMENTED:
|
||||||
// Blue
|
// Blue
|
||||||
printf("\x1b[34mTest not implemented: %s\n\x1b[0m", reports.tests[i].name);
|
printf("\x1b[34mTest not implemented: %s\n\x1b[0m", reports.tests[i].name.str);
|
||||||
counts->not_implemented += 1;
|
counts->not_implemented += 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Bright Red
|
// Bright Red
|
||||||
printf("\x1b[91mTest errored: %s\n\tUnknown test result status.\n\x1b[0m", reports.tests[i].name);
|
printf("\x1b[91mTest errored: %s\n\tUnknown test result status.\n\x1b[0m", reports.tests[i].name.str);
|
||||||
counts->errored += 1;
|
counts->errored += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -78,10 +78,12 @@ int main(void) {
|
||||||
.total = 0,
|
.total = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
TestsReport lexer_reports = run_lexer_tests();
|
printf(" ========== SlsStr Tests ==========\n");
|
||||||
lexer_test_report(lexer_reports, &counts);
|
test_report(run_string_tests(), &counts);
|
||||||
|
printf(" ========== Lexer Tests ==========\n");
|
||||||
|
test_report(run_lexer_tests(), &counts);
|
||||||
|
|
||||||
printf(" ===== Tests Overview =====\n");
|
printf(" ========== Tests Overview ==========\n");
|
||||||
if (counts.errored > 0)
|
if (counts.errored > 0)
|
||||||
// Bright Red
|
// Bright Red
|
||||||
printf("\x1b[91m%d of %d tests encountered an error.\n\x1b[0m", counts.errored, counts.total);
|
printf("\x1b[91m%d of %d tests encountered an error.\n\x1b[0m", counts.errored, counts.total);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ file_headers = """\
|
||||||
main_header = """\
|
main_header = """\
|
||||||
TestsReport run_lexer_tests() {
|
TestsReport run_lexer_tests() {
|
||||||
TestsReport test_report = (TestsReport) {
|
TestsReport test_report = (TestsReport) {
|
||||||
.section = "lexer_tests",
|
.section = SLS_STR("lexer_tests"),
|
||||||
.count = NUM_OF_TESTS,
|
.count = NUM_OF_TESTS,
|
||||||
.tests = (TestResult *)malloc(sizeof(TestResult) * NUM_OF_TESTS),
|
.tests = (TestResult *)malloc(sizeof(TestResult) * NUM_OF_TESTS),
|
||||||
};
|
};
|
||||||
|
|
@ -73,7 +73,7 @@ def _token_to_c_call(token: dict, idx_var="i") -> str:
|
||||||
elif ttype == "identifier_literal":
|
elif ttype == "identifier_literal":
|
||||||
return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{TRUE, {len(value)}, "{value}"}})' # type: ignore
|
return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{TRUE, {len(value)}, "{value}"}})' # type: ignore
|
||||||
elif ttype == "error":
|
elif ttype == "error":
|
||||||
return f'test_for_error(&test, result, i++, &(TestErrorMessage){{{len(value)+1}, "{c_string_literal(value)}"}})' # type: ignore
|
return f'test_for_error(&test, result, i++, SLS_STR("{c_string_literal(value)}"))' # type: ignore
|
||||||
else:
|
else:
|
||||||
raise ValueError(f' Unhandled token type: {ttype}')
|
raise ValueError(f' Unhandled token type: {ttype}')
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@ def generate_c_test(test: dict) -> str:
|
||||||
|
|
||||||
# Function header
|
# Function header
|
||||||
c_code = [f"static TestResult {name}() {{",
|
c_code = [f"static TestResult {name}() {{",
|
||||||
f' LexerTest test = start_up_test("{name}", "{code}");',
|
f' LexerTest test = start_up_test(SLS_STR("{name}"), SLS_STR("{code}"));',
|
||||||
" LexerResult result = lexical_analysis(&test.lexer_info);",
|
" LexerResult result = lexical_analysis(&test.lexer_info);",
|
||||||
" if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);",
|
" if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);",
|
||||||
" size_t i = 0;"]
|
" size_t i = 0;"]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue