Updated to new string type

This commit is contained in:
Kyler Olsen 2025-11-08 01:02:01 -07:00
parent a5b119807d
commit 2ebe34a9a6
11 changed files with 356 additions and 479 deletions

View File

@ -3,7 +3,8 @@
## Formats
- `c` char\*
- `y` char\*
- `c` char
- `d` int32_t
- `l` int64_t
- `u` uint64_t

View File

@ -14,8 +14,8 @@
extern const size_t TYPE_NAMES_SAFE_LENGTH;
typedef struct {
const char *filename;
const char *source_code;
SlsStr filename;
SlsStr source_code;
size_t pos;
size_t column;
size_t line;
@ -56,8 +56,7 @@ typedef enum {
extern const char *ARRAY_TYPES_NAMES[];
typedef struct {
const char *name;
size_t length;
SlsStr name;
Boolean is_literal;
} Identifier;
@ -79,11 +78,6 @@ typedef struct {
IntegerBuiltInType type;
} IntegerLiteral;
typedef struct {
const char *value;
size_t length;
} StringLiteral;
typedef struct Token Token;
typedef struct {
@ -100,7 +94,7 @@ typedef struct {
typedef struct {
void **values;
const char *name;
SlsStr name;
} StructInline;
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, }
float *float_literals; // type == ARRAY_FLOAT
double *double_literals; // type == ARRAY_DOUBLE
StringLiteral *string_literals; // type == ARRAY_STRING
SlsStr *string_literals; // type == ARRAY_STRING
Boolean *boolean_literals; // type == ARRAY_BOOLEAN
TokenString *token_strings; // type == ARRAY_TOKEN_STRING
TypeTuple *type_tuples; // type == ARRAY_TYPE_TUPLE
@ -127,7 +121,7 @@ struct Token {
IntegerLiteral integer_literal; // type == TOKEN_INTEGER
float float_literal; // type == TOKEN_FLOAT
double double_literal; // type == TOKEN_DOUBLE
StringLiteral string_literal; // type == TOKEN_STRING
SlsStr string_literal; // type == TOKEN_STRING
Boolean boolean_literal; // type == TOKEN_BOOLEAN
ArrayLiteral array_literal; // type == TOKEN_ARRAY
TokenString token_string; // type == TOKEN_TOKEN_STRING
@ -153,7 +147,7 @@ typedef struct {
};
} 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);
void clean_token_result(LexerTokenResult *head);
LexerResult lexical_analysis(LexerInfo *lexer_info);

View File

@ -25,6 +25,7 @@ size_t strnlen(const char *s, size_t maxlen);
SlsStr malloc_str(const char *s, size_t maxlen);
SlsStr new_str(size_t length);
SlsStr copy_str(SlsStr s);
int32_t compare_str(SlsStr a, SlsStr b);
void free_str(SlsStr *s);
SlsStr format(const SlsStr s, ...);

View File

@ -28,8 +28,7 @@ typedef struct {
typedef struct {
Boolean is_literal;
size_t length;
const char *name;
SlsStr name;
} TestIdentifierValue;
typedef struct {
@ -37,11 +36,6 @@ typedef struct {
uint64_t value;
} TestIntegerValue;
typedef struct {
size_t length;
const char *string;
} TestStringValue;
typedef struct {
size_t dimensions;
size_t *shape;
@ -69,7 +63,7 @@ typedef struct {
typedef struct {
size_t dimensions;
size_t *shape;
TestStringValue *values;
SlsStr *values;
} TestArrayStringValue;
typedef struct {
@ -81,8 +75,7 @@ typedef struct {
typedef struct {
size_t dimensions;
size_t *shape;
size_t struct_name_length;
const char *struct_name;
SlsStr struct_name;
Boolean (*struct_handler)(LexerTest *, LexerResult, size_t, size_t, void *, void *);
void **values;
} TestArrayStructInlineValue;
@ -104,15 +97,10 @@ typedef struct {
TestIdentifierValue *output_values;
} TestTypeTupleValue;
typedef struct {
size_t length;
const char *message;
} TestErrorMessage;
LexerTest start_up_test(const char *test_name, const char *test_code);
LexerTest start_up_test(SlsStr test_name, SlsStr test_code);
void clean_up_test(LexerResult result);
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 skip_test(LexerTest *test, LexerResult result);
TestResult skip_test_no_result(LexerTest *test);
@ -123,7 +111,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_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_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_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);
@ -134,6 +122,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_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_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

View File

@ -9,8 +9,9 @@
#include <stddef.h>
#include "sls/errors.h"
#include "sls/string.h"
extern const char *TEST_FILE_NAME;
extern const SlsStr TEST_FILE_NAME;
typedef enum {
TEST_ERROR, // The test encountered an error
@ -22,16 +23,16 @@ typedef enum {
} TestResultType;
typedef struct {
const char *name;
SlsStr name;
TestResultType status;
union {
char *message; // status in { TEST_LOGIC_FAIL, }
SlsStr message; // status in { TEST_LOGIC_FAIL, }
SlsError error; // status in { TEST_ERROR, TEST_ERROR_FAIL, }
};
} TestResult;
typedef struct {
const char *section;
SlsStr section;
size_t count;
TestResult* tests;
} TestsReport;

View File

@ -59,7 +59,7 @@ const char *INTEGER_TYPES_NAMES[] = {
"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
lexer_info->filename = filename;
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) {
// 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) {
// 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) {
// 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) {
// 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) {
// 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
lexer_info->line++;
lexer_info->column = 1;
@ -110,14 +110,14 @@ static char advance(LexerInfo *lexer_info) {
lexer_info->column++;
}
// 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) {
// Create a LexerTokenResult to store the results of lexing the current token
LexerTokenResult *result = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
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->result = token;
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};
}
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
LexerTokenResult *result = (LexerTokenResult *)malloc(sizeof(LexerTokenResult));
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->error.message = message;
result->error.code = 1;
@ -197,7 +197,7 @@ static IntegerTypeResult get_integer_type(NumericTypes numeric_type) {
integer_type = INTEGER_U8;
break;
default:
return (IntegerTypeResult){SLS_ERROR, .error = (SlsError){.message = "Lexer Error: Encountered a Float where there should not be one.", .code = 1}};
return (IntegerTypeResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer Error: Encountered a Float where there should not be one."), 1}};
}
return (IntegerTypeResult){SLS_RESULT, .integer_type = integer_type};
}
@ -322,58 +322,42 @@ static uint64_t create_hexadecimal_integer(LexerInfo *lexer_info, size_t start)
static LexerResult create_integer_token(LexerInfo *lexer_info, IntegerBuiltInType type, uint64_t value, size_t start, size_t start_line) {
switch (type) {
case INTEGER_I64: break;
case INTEGER_U64: break;
case INTEGER_I32:
if (value > (uint64_t)UINT32_MAX) {
char *error_message = (char *)malloc(sizeof(char) * 47);
strncpy(error_message, "Integer overflow: value exceeds range for i32.", 47);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for i32."), start, start_line);
}
break;
case INTEGER_I16:
if (value > (uint64_t)UINT16_MAX) {
char *error_message = (char *)malloc(sizeof(char) * 47);
strncpy(error_message, "Integer overflow: value exceeds range for i16.", 47);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for i16."), start, start_line);
}
break;
case INTEGER_I8:
if (value > (uint64_t)UINT8_MAX) {
char *error_message = (char *)malloc(sizeof(char) * 46);
strncpy(error_message, "Integer overflow: value exceeds range for i8.", 46);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for i8."), start, start_line);
}
break;
case INTEGER_U32:
if (seek(lexer_info, start) == '-') {
char *error_message = (char *)malloc(sizeof(char) * 48);
strncpy(error_message, "Integer overflow: value exceeds range for u32.", 48);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for u32."), start, start_line);
} if (value > (uint64_t)UINT32_MAX) {
char *error_message = (char *)malloc(sizeof(char) * 47);
strncpy(error_message, "Integer overflow: value exceeds range for u32.", 47);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for u32."), start, start_line);
}
break;
case INTEGER_U16:
if (seek(lexer_info, start) == '-') {
char *error_message = (char *)malloc(sizeof(char) * 48);
strncpy(error_message, "Integer overflow: value exceeds range for u16.", 48);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for u16."), start, start_line);
} if (value > (uint64_t)UINT16_MAX) {
char *error_message = (char *)malloc(sizeof(char) * 47);
strncpy(error_message, "Integer overflow: value exceeds range for u16.", 47);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for u16."), start, start_line);
}
break;
case INTEGER_U8:
if (seek(lexer_info, start) == '-') {
char *error_message = (char *)malloc(sizeof(char) * 47);
strncpy(error_message, "Integer overflow: value exceeds range for u8.", 47);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for u8."), start, start_line);
} if (value > (uint64_t)UINT8_MAX) {
char *error_message = (char *)malloc(sizeof(char) * 46);
strncpy(error_message, "Integer overflow: value exceeds range for u8.", 46);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Integer overflow: value exceeds range for u8."), start, start_line);
}
break;
}
@ -405,14 +389,10 @@ static LexerResult parse_numeric_type(LexerInfo *lexer_info, char c, size_t star
c = advance(lexer_info);
c = advance(lexer_info);
} else {
char *error_message = (char *)malloc(sizeof(char) * 52);
strncpy(error_message, "Invalid float type: must be of type 'f64' or 'f32'.", 52);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Invalid float type: must be of type 'f64' or 'f32'."), start, start_line);
}
} else {
char *error_message = (char *)malloc(sizeof(char) * 49);
strncpy(error_message, "Invalid numeric literal: float type not allowed.", 49);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Invalid numeric literal: float type not allowed."), start, start_line);
}
} else if (c == 'i' || c == 'u') {
if (c == 'u') numeric_type |= NUMERIC_UNSIGNED;
@ -434,24 +414,16 @@ static LexerResult parse_numeric_type(LexerInfo *lexer_info, char c, size_t star
c = advance(lexer_info);
} else {
if (numeric_type & NUMERIC_UNSIGNED) {
char *error_message = (char *)malloc(sizeof(char) * 78);
strncpy(error_message, "Invalid unsigned integer type: must be of type 'u64', 'u32', 'u16', and 'u8'.", 78);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Invalid unsigned integer type: must be of type 'u64', 'u32', 'u16', and 'u8'."), start, start_line);
} else {
char *error_message = (char *)malloc(sizeof(char) * 76);
strncpy(error_message, "Invalid signed integer type: must be of type 'i64', 'i32', 'i16', and 'i8'.", 76);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Invalid signed integer type: must be of type 'i64', 'i32', 'i16', and 'i8'."), start, start_line);
}
}
} else {
if (numeric_literal_type == NUMERIC_DECIMAL || numeric_literal_type == NUMERIC_FLOAT || numeric_literal_type == NUMERIC_EXPONENTIAL) {
char *error_message = (char *)malloc(sizeof(char) * 61);
strncpy(error_message, "Invalid numeric type: type must start with 'f', 'i', or 'u'.", 61);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Invalid numeric type: type must start with 'f', 'i', or 'u'."), start, start_line);
} else {
char *error_message = (char *)malloc(sizeof(char) * 55);
strncpy(error_message, "Invalid integer type: type must start with 'i' or 'u'.", 55);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, SLS_STR("Invalid integer type: type must start with 'i' or 'u'."), start, start_line);
}
} if (isspace(c) || c == '/' || c == '\0') {
IntegerTypeResult integer_type = get_integer_type(numeric_type);
@ -480,11 +452,9 @@ static LexerResult parse_numeric_type(LexerInfo *lexer_info, char c, size_t star
case NUMERIC_EXPONENTIAL:
break;
}
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Numeric Literal Not Implemented Error.", 1}};
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Numeric Literal Not Implemented Error."), 1}};
}
char *error_message = (char *)malloc(sizeof(char) * 57);
snprintf(error_message, 57, "Invalid numeric literal: unexpected '%c' in numeric type.", c);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, format(SLS_STR("Invalid numeric literal: unexpected '%c' in numeric type."), c), start, start_line);
}
static LexerResult parse_binary_integer(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
@ -494,9 +464,7 @@ static LexerResult parse_binary_integer(LexerInfo *lexer_info, char c, size_t st
uint64_t value = create_binary_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line);
}
char *error_message = (char *)malloc(sizeof(char) * 58);
snprintf(error_message, 58, "Invalid binary literal: unexpected '%c' in binary integer.", c);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, format(SLS_STR("Invalid binary literal: unexpected '%c' in binary integer."), c), start, start_line);
}
static LexerResult parse_octal_integer(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
@ -506,19 +474,17 @@ static LexerResult parse_octal_integer(LexerInfo *lexer_info, char c, size_t sta
uint64_t value = create_octal_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line);
}
char *error_message = (char *)malloc(sizeof(char) * 56);
snprintf(error_message, 56, "Invalid octal literal: unexpected '%c' in octal integer.", c);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, format(SLS_STR("Invalid octal literal: unexpected '%c' in octal integer."), c), start, start_line);
}
static LexerResult parse_exponential(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
(void)lexer_info; (void)c; (void)start; (void)start_line;
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Float Exponential Not Implemented Error.", 1}};
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Float Exponential Not Implemented Error."), 1}};
}
static LexerResult parse_float(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
(void)lexer_info; (void)c; (void)start; (void)start_line;
return (LexerResult){SLS_ERROR, .error = (SlsError){"Lexer: Float Not Implemented Error.", 1}};
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Float Not Implemented Error."), 1}};
}
static LexerResult parse_decimal_integer(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
@ -530,9 +496,7 @@ static LexerResult parse_decimal_integer(LexerInfo *lexer_info, char c, size_t s
uint64_t value = create_decimal_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line);
}
char *error_message = (char *)malloc(sizeof(char) * 60);
snprintf(error_message, 60, "Invalid decimal literal: unexpected '%c' in decimal integer.", c);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, format(SLS_STR("Invalid decimal literal: unexpected '%c' in decimal integer."), c), start, start_line);
}
static LexerResult parse_hexadecimal_integer(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
@ -542,9 +506,7 @@ static LexerResult parse_hexadecimal_integer(LexerInfo *lexer_info, char c, size
uint64_t value = create_hexadecimal_integer(lexer_info, start);
return create_integer_token(lexer_info, INTEGER_I64, value, start, start_line);
}
char *error_message = (char *)malloc(sizeof(char) * 68);
snprintf(error_message, 68, "Invalid hexadecimal literal: unexpected '%c' in hexadecimal integer.", c);
return lexer_error(lexer_info, error_message, start, start_line);
return lexer_error(lexer_info, format(SLS_STR("Invalid hexadecimal literal: unexpected '%c' in hexadecimal integer."), c), start, start_line);
}
static LexerResult parse_numeric_literal(LexerInfo *lexer_info, char c, size_t start, size_t start_line) {
@ -567,32 +529,32 @@ static LexerResult parse_numeric_literal(LexerInfo *lexer_info, char c, size_t s
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;
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) {
(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) {
(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) {
(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) {
(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) {
(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) {
@ -628,7 +590,7 @@ static LexerResult lexer_next(LexerInfo *lexer_info) {
// Identifiers and Booleans
if (isascii(c)) return parse_identifiers_and_booleans(lexer_info, c, start, start_line);
// 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) {
@ -636,7 +598,10 @@ void clean_token_result(LexerTokenResult *head) {
LexerTokenResult *next;
while (head) {
next = head->next;
if (head->type == SLS_ERROR) free(head->error.message);
if (head->type == SLS_ERROR) free_str(&head->error.message);
else {
if (head->result.type == TOKEN_STRING) free_str(&head->error.message);
}
if (head) free(head);
head = next;
}
@ -678,7 +643,7 @@ LexerResult lexical_analysis(LexerInfo *lexer_info) {
// Current should not be null_ptr
if (current == 0) {
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);

View File

@ -8,6 +8,8 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <stdlib.h>
#include "sls/string.h"
#include "sls/lexer.h"
@ -40,9 +42,13 @@ SlsStr copy_str(SlsStr s) {
return malloc_str(s.str, s.len);
}
int32_t compare_str(SlsStr a, SlsStr b) {
return strcmp(a.str, b.str);
}
void free_str(SlsStr *s) {
if (s->allocated) {
free(s->str);
free((void *)s->str);
s->len = 0;
s->str = 0;
s->allocated = FALSE;
@ -51,6 +57,7 @@ void free_str(SlsStr *s) {
typedef enum {
FORMAT_C_STRINGS,
FORMAT_CHARACTER,
FORMAT_INTEGER_32,
FORMAT_INTEGER_64,
FORMAT_UNSIGNED_INTEGER_64,
@ -68,6 +75,7 @@ typedef struct {
FormatStringTypes type;
union {
const char *c_string;
char character;
int32_t integer_32;
int64_t integer_64;
uint64_t unsigned_integer_64;
@ -91,6 +99,7 @@ SlsStr format(const SlsStr s, ...) {
const char *current = strchr(s.str, '%');
do {
switch (current[1]) {
case 'y':
case 'c':
case 'd':
case 'l':
@ -106,7 +115,8 @@ SlsStr format(const SlsStr s, ...) {
count++;
break;
}
} while (current = strchr(current + 2, '%'));
current = strchr(current + 2, '%');
} while (current);
FormatStringItem *items = (FormatStringItem *)malloc(sizeof(FormatStringItem) * count);
size_t i = 0;
@ -114,10 +124,14 @@ SlsStr format(const SlsStr s, ...) {
current = strchr(s.str, '%');
do {
switch (current[1]) {
case 'c':
case 'y':
items[i].type = FORMAT_C_STRINGS;
items[i].c_string = va_arg(args, const char *);
break;
case 'c':
items[i].type = FORMAT_CHARACTER;
items[i].character = va_arg(args, int);
break;
case 'd':
items[i].type = FORMAT_INTEGER_32;
items[i].integer_32 = va_arg(args, int32_t);
@ -163,10 +177,11 @@ SlsStr format(const SlsStr s, ...) {
items[i].boolean = va_arg(args, Boolean);
break;
}
items[i].str_index = current - last_index;
last_index = current + 2;
items[i].str_index = (size_t)(current - last_index);
last_index = (size_t)(current + 2);
i++;
} while (current = strchr(current + 2, '%'));
current = strchr(current + 2, '%');
} while (current);
size_t length = s.len - (count * 2);
for (size_t i = 0; i < count; i++) {
@ -174,6 +189,9 @@ SlsStr format(const SlsStr s, ...) {
case FORMAT_C_STRINGS:
length += items[i].self_length = strlen(items[i].c_string);
break;
case FORMAT_CHARACTER:
length += items[i].self_length = 1;
break;
case FORMAT_INTEGER_32:
length += items[i].self_length = ceil(log10(items[i].integer_32 + 1));
break;
@ -226,11 +244,14 @@ SlsStr format(const SlsStr s, ...) {
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, "%d", items[item_i].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);
@ -242,7 +263,7 @@ SlsStr format(const SlsStr s, ...) {
snprintf(temp, items[item_i].self_length + 1, "%.2f", items[item_i].ffloat);
break;
case FORMAT_SLS_STR:
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].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]);
@ -254,7 +275,7 @@ SlsStr format(const SlsStr s, ...) {
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);
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].error.message.str);
break;
case FORMAT_SLS_BOOLEAN:
if (items[item_i].boolean) memcpy(temp, "TRUE", 5);

View File

@ -20,7 +20,7 @@ static const double FLOAT_TEST_PRECISION = 0.01;
// 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) {
.result = (TestResult) {
.name = test_name, .status = TEST_NOT_IMPLEMENTED } };
@ -36,13 +36,13 @@ void clean_up_test(LexerResult result) {
TestResult error_test(LexerTest *test, LexerResult result, SlsError error) {
test->result.status = TEST_ERROR;
test->result.error = error;
test->result.error.message = copy_str(error.message);
clean_up_test(result);
return test->result;
}
TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message) {
if (message == 0) return error_test(test, result, (SlsError) {
.message = "Out of Memory Error!", .code = 1, });
TestResult logic_fail_test(LexerTest *test, LexerResult result, SlsStr message) {
test->result.status = TEST_LOGIC_FAIL;
test->result.message = message;
clean_up_test(result);
@ -52,11 +52,7 @@ TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message) {
TestResult logic_error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
test->result.status = TEST_LOGIC_ERROR_FAIL;
test->result.error = error;
size_t message_length = strlen(error.message) + 1;
const char *message = (char *)malloc(sizeof(char) * message_length);
strncpy(message, error.message, message_length);
test->result.error.message = message;
test->result.error.message = copy_str(error.message);
clean_up_test(result);
return test->result;
@ -65,6 +61,8 @@ TestResult logic_error_fail_test(LexerTest *test, LexerResult result, SlsError e
TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
test->result.status = TEST_ERROR_FAIL;
test->result.error = error;
test->result.error.message = copy_str(error.message);
clean_up_test(result);
return test->result;
}
@ -88,191 +86,99 @@ TestResult pass_test(LexerTest *test, LexerResult result) {
// Test messages
static char *unexpected_end_of_token_stream(size_t i) {
size_t length = ceil(log10(i)) + 47;
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 SlsStr unexpected_end_of_token_stream(size_t i) {
return format(SLS_STR("Unexpected end of token stream (%z tokens found)"), i - 1);
}
static char *expected_end_of_token_stream(size_t i) {
size_t length = ceil(log10(i)) + 47;
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 SlsStr expected_end_of_token_stream(size_t i) {
return format(SLS_STR("Expected end of token stream (more than %z tokens found)"), i - 1);
}
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;
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 SlsStr token_should_be(size_t i, TokenType should, TokenType found) {
return format(SLS_STR("Token #%z should be a %t, but found a %t"), i, should, 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;
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 SlsStr integer_type_should_be(size_t i, IntegerBuiltInType should, IntegerBuiltInType found) {
return format(SLS_STR("Token #%z integer type should be a %i, but found a %i"), i, should, 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;
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 SlsStr integer_value_should_be(size_t i, uint64_t should, uint64_t found) {
return format(SLS_STR("Token #%z integer value should be %i, but found %i"), i, should, 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;
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 SlsStr float_value_should_be(size_t i, double should, double found) {
return format(SLS_STR("Token #%z float value should be %f, but found %f"), i, should, found);
}
static char *identifier_should_be_literal(size_t i) {
size_t length = ceil(log10(i + 1)) + 51;
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 SlsStr identifier_should_be_literal(size_t i) {
return format(SLS_STR("Token #%z identifier should be an identifier literal"), i);
}
static char *identifier_should_not_be_literal(size_t i) {
size_t length = ceil(log10(i + 1)) + 55;
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 SlsStr identifier_should_not_be_literal(size_t i) {
return format(SLS_STR("Token #%z identifier should not be an identifier literal"), i);
}
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;
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 SlsStr token_length_should_be(size_t i, TokenType type, uint64_t should, uint64_t found) {
return format(SLS_STR("Token #%z of type %t length should be %u, but found %u"), i, type, should, 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;
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 SlsStr token_value_string_should_be(size_t i, TokenType type, SlsStr should, SlsStr found) {
return format(SLS_STR("Token #%z of type %t string value should be %s, but found %s"), i, type, should, found);
}
static char *boolean_should_be(size_t i, Boolean value) {
size_t length = ceil(log10(i + 1)) + 45;
char *string = (char *)malloc(sizeof(char) * length);
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 SlsStr boolean_should_be(size_t i, Boolean value) {
if (value) return format(SLS_STR("Token #%z boolean should be true, but is false"), i);
else return format(SLS_STR("Token #%z boolean should be false, but is true"), i);
}
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;
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 SlsStr array_type_should_be(size_t i, ArrayType should, ArrayType found) {
return format(SLS_STR("Token #%z should be a %a, but found a %a"), i, should, 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;
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 SlsStr array_dimensions_should_be(size_t i, size_t should, size_t found) {
return format(SLS_STR("Token #%z array dimensions should be %z, but found %z"), i, should, 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;
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 SlsStr array_dimension_shape_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) {
return format(SLS_STR("Token #%z dimension %z of array type %a should be shape %u, but found %u"), i, j, type, should, 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;
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 SlsStr array_element_integer_should_be(size_t i, size_t j, ArrayType type, uint64_t should, uint64_t found) {
return format(SLS_STR("Token #%z element %z of array type %a should be %u, but found %u"), i, j, type, should, 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;
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 SlsStr array_element_float_should_be(size_t i, size_t j, ArrayType type, double should, double found) {
return format(SLS_STR("Token #%z element %z of array type %a should be %f, but found %f"), i, j, type, should, 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;
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 SlsStr array_element_string_should_be(size_t i, size_t j, ArrayType type, SlsStr should, SlsStr found) {
return format(SLS_STR("Token #%z element %z of array type %a should be %s, but found %s"), i, j, type, should, found);
}
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;
char *string = (char *)malloc(sizeof(char) * length);
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 SlsStr array_element_boolean_should_be(size_t i, size_t j, ArrayType type, Boolean value) {
if (value) return format(SLS_STR("Token #%z element %z of array type %a should be true, but is false"), i, j, type);
else return format(SLS_STR("Token #%z element %z of array type %a should be false, but is true"), i, j, type);
}
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;
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 SlsStr type_tuple_element_integer_should_be(size_t i, size_t j, uint64_t should, uint64_t found) {
return format(SLS_STR("Token #%z element %u of type tuple should be %u, but found %u"), i, j, should, 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;
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 SlsStr type_tuple_element_string_should_be(size_t i, size_t j, SlsStr should, SlsStr found) {
return format(SLS_STR("Token #%z element %z of type tuple should be %s, but found %s"), i, j, should, found);
}
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;
char *string = (char *)malloc(sizeof(char) * length);
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 SlsStr type_tuple_element_boolean_should_be(size_t i, size_t j, Boolean value) {
if (value) return format(SLS_STR("Token #%z element %z of type tuple should be true, but is false"), i, j);
else return format(SLS_STR("Token #%z element %z of type tuple should be false, but is true"), i, j);
}
static char *token_should_be_error(size_t i, TestErrorMessage should, TokenType found) {
size_t length = ceil(log10(i + 1)) + should.length + strnlen(TOKEN_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 72;
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 SlsStr token_should_be_error(size_t i, SlsStr should, TokenType found) {
return format(SLS_STR("Token #%z should be an error with a message of \"%s\", but found token of type %t"), i, should, found);
}
static char *error_should_be(size_t i, TestErrorMessage should, SlsError found) {
size_t length = ceil(log10(i + 1)) + should.length + strlen(found.message) + 77;
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;
static SlsStr error_should_be(size_t i, SlsStr should, SlsError found) {
return format(SLS_STR("Token #%z should be an error with a message of \"%s\", but found error with message \"%e\""), i, should, found);
}
// Test parts
@ -305,7 +211,7 @@ static Boolean test_array_type(LexerTest *test, LexerResult result, size_t i, Ar
}
for (size_t j = 0; j < dimensions; 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;
}
}
@ -333,11 +239,11 @@ Boolean test_identifier_value(LexerTest *test, LexerResult result, size_t i, Tes
} 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));
return TRUE;
} if (head->result.identifier.length == strnlen(value->name, value->length)) {
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->name, value->length), head->result.identifier.length));
} if (head->result.identifier.name.len == value->name.len) {
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, value->name.len, head->result.identifier.name.len));
return TRUE;
} if (strncmp(head->result.identifier.name, value->name, value->length) != 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));
} if (compare_str(head->result.identifier.name, value->name) != 0) {
logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, head->result.identifier.name, value->name));
return TRUE;
}
return FALSE;
@ -382,16 +288,16 @@ Boolean test_double_value(LexerTest *test, LexerResult result, size_t i, double
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;
LexerTokenResult *head = get_token(result.result, i);
if (test_token_type(test, result, i, token_type)) {
return TRUE;
} if (head->result.string_literal.length == strnlen(value->string, value->length)) {
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, strnlen(value->string, value->length), head->result.string_literal.length));
} if (head->result.string_literal.len == value.len) {
logic_fail_test(test, result, token_length_should_be(i + 1, token_type, value.len, head->result.string_literal.len));
return TRUE;
} if (strncmp(head->result.string_literal.value, value->string, value->length) != 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));
} if (compare_str(head->result.string_literal, value) != 0) {
logic_fail_test(test, result, token_value_string_should_be(i + 1, token_type, value, head->result.string_literal));
return TRUE;
}
return FALSE;
@ -418,11 +324,11 @@ Boolean test_array_identifier_value(LexerTest *test, LexerResult result, size_t
size_t length = 1;
for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (size_t j = 0; j < length; j++) {
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));
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].name.len, head->result.array_literal.identifiers[j].name.len));
return TRUE;
} if (strncmp(head->result.array_literal.identifiers[j].name, values->values[j].name, values->values[j].length)) {
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));
} if (compare_str(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].name, head->result.array_literal.identifiers[j].name));
return TRUE;
} 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));
@ -492,11 +398,11 @@ Boolean test_array_string_value(LexerTest *test, LexerResult result, size_t i, T
size_t length = 1;
for (size_t j = 0; j < values->dimensions; j++) length *= values->shape[j];
for (size_t j = 0; j < length; j++) {
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));
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].len, head->result.array_literal.string_literals[j].len));
return TRUE;
} if (strncmp(head->result.array_literal.string_literals[j].value, values->values[j].string, values->values[j].length)) {
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));
} if (compare_str(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], head->result.array_literal.string_literals[j]));
return TRUE;
}
}
@ -525,8 +431,8 @@ Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size
LexerTokenResult *head = get_token(result.result, i);
if (test_array_type(test, result, i, array_type, values->shape, values->dimensions)) {
return TRUE;
} 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, TOKEN_IDENTIFIER, values->struct_name_length, values->struct_name, head->result.array_literal.struct_inline.name));
} if (compare_str(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, head->result.array_literal.struct_inline.name));
return TRUE;
}
size_t length = 1;
@ -582,22 +488,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));
return TRUE;
} for (size_t j = 0; j < values->input_length; j++) {
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));
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].name.len, head->result.type_tuple.input_identifiers[j].name.len));
return TRUE;
} if (strncmp(head->result.type_tuple.input_identifiers[j].name, values->input_values[j].name, values->input_values[j].length)) {
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));
} if (compare_str(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].name, head->result.type_tuple.input_identifiers[j].name));
return TRUE;
} 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));
return TRUE;
}
} for (size_t j = 0; j < values->output_length; j++) {
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));
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].name.len, head->result.type_tuple.output_identifiers[j].name.len));
return TRUE;
} if (strncmp(head->result.type_tuple.output_identifiers[j].name, values->output_values[j].name, values->input_values[j].length)) {
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));
} if (compare_str(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].name, head->result.type_tuple.output_identifiers[j].name));
return TRUE;
} 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));
@ -607,13 +513,13 @@ Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, Tes
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);
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;
} if (strncmp(head->error.message, error->message, error->length+1) != 0) {
logic_fail_test(test, result, error_should_be(i + 1, *error, head->error));
} if (compare_str(head->error.message, error) != 0) {
logic_fail_test(test, result, error_should_be(i + 1, error, head->error));
return TRUE;
}
return FALSE;

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@
#include "sls/errors.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 {
uint16_t errored;
@ -28,39 +28,39 @@ static void lexer_test_report(TestsReport reports, TestCounts *counts) {
switch (reports.tests[i].status) {
case TEST_ERROR:
// 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;
break;
case TEST_ERROR_FAIL:
// 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;
break;
case TEST_LOGIC_ERROR_FAIL:
// 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;
free(reports.tests[i].message);
free_str(&reports.tests[i].message);
break;
case TEST_LOGIC_FAIL:
// 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;
free(reports.tests[i].message);
free_str(&reports.tests[i].message);
break;
case TEST_PASS:
// 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;
break;
case TEST_NOT_IMPLEMENTED:
// 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;
break;
default:
// 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;
break;
}

View File

@ -27,7 +27,7 @@ file_headers = """\
main_header = """\
TestsReport run_lexer_tests() {
TestsReport test_report = (TestsReport) {
.section = "lexer_tests",
.section = SLS_STR("lexer_tests"),
.count = 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":
return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{TRUE, {len(value)}, "{value}"}})' # type: ignore
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:
raise ValueError(f' Unhandled token type: {ttype}')
@ -89,7 +89,7 @@ def generate_c_test(test: dict) -> str:
# Function header
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);",
" if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);",
" size_t i = 0;"]