White space breaks stuff, but other than that its good

This commit is contained in:
Kyler Olsen 2025-11-20 15:42:40 -07:00
parent f8894ea4c0
commit f2033e30e9
5 changed files with 2637 additions and 110 deletions

View File

@ -657,9 +657,48 @@ static LexerResult parse_type_tuples(LexerInfo *lexer_info, char c, size_t start
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Type Tuples Not Implemented Error."), 1}};
}
Boolean is_identifier_continue(LexerInfo *lexer_info, char c) {
if (!isprint(c)) return FALSE;
if (c == '/' && far_peek(lexer_info, 1) == '/') return FALSE;
if (c == '{' || c == '}') return FALSE;
if (c == '[' || c == ']') return FALSE;
if (c == '(' || c == ')') return FALSE;
if (c == '\'' || c == '"') return FALSE;
if (c == '.' || c == ':' || c == '#') return FALSE;
if (isspace(c) || c == '\0') return FALSE;
return TRUE;
}
Boolean is_identifier_start(LexerInfo *lexer_info, char c) {
if (c == ':' && far_peek(lexer_info, 1) == ':') c = far_peek(lexer_info, 2);
if ((!isdigit(c)) && is_identifier_continue(lexer_info, c)) return TRUE;
else return FALSE;
}
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){SLS_STR("Lexer: Identifiers and Booleans Not Implemented Error."), 1}};
Boolean literal = FALSE;
if (c == ':' && far_peek(lexer_info, 1) == ':') {
literal = TRUE;
c = advance(lexer_info);
c = advance(lexer_info);
}
size_t length = 0;
while (is_identifier_continue(lexer_info, c)) {
c = advance(lexer_info);
length++;
}
char *name_value = (char *)calloc(length+1, sizeof(char));
for (size_t i = 0; i < length; i++)
name_value[i] = lexer_info->source_code.str[i + (2 * literal)];
SlsStr name = sls_str_malloc(name_value, length);
free(name_value);
if (sls_str_cmp(name, SLS_STR("false")) == 0)
return lexer_result(lexer_info, (Token){TOKEN_BOOLEAN, .boolean_literal = FALSE}, start, start_line);
else if (sls_str_cmp(name, SLS_STR("true")) == 0)
return lexer_result(lexer_info, (Token){TOKEN_BOOLEAN, .boolean_literal = TRUE}, start, start_line);
else
return lexer_result(lexer_info, (Token){TOKEN_IDENTIFIER, .identifier = (Identifier){.is_literal = literal, .name = name}}, start, start_line);
}
static LexerResult lexer_next(LexerInfo *lexer_info) {
@ -697,7 +736,8 @@ static LexerResult lexer_next(LexerInfo *lexer_info) {
// Type Tuples
if (c == '(') return parse_type_tuples(lexer_info, c, start, start_line);
// Identifiers and Booleans
if (sls_isascii(c)) return parse_identifiers_and_booleans(lexer_info, c, start, start_line);
if (is_identifier_start(lexer_info, c))
return parse_identifiers_and_booleans(lexer_info, c, start, start_line);
// Lexing Error
return (LexerResult){SLS_ERROR, .error = (SlsError){SLS_STR("Lexer: Unknown Character Error."), 1}};
}

View File

@ -265,7 +265,7 @@ 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.name.len == value->name.len) {
} 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 (sls_str_cmp(head->result.identifier.name, value->name) != 0) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,10 @@ class IdentifierTestGenerator(BaseTestGenerator):
# All caps with underscores
self.make_success_test("Identifier All Caps", "MY_CONSTANT",
"identifier", "MY_CONSTANT")
# Others
self.make_success_test("Identifier With Dash", "my-var",
"identifier_literal", "my-var")
def generate_identifier_literal_tests(self):
"""Generate identifier literal tests (with :: prefix)."""
@ -113,7 +117,7 @@ class IdentifierTestGenerator(BaseTestGenerator):
"identifier", "hello")
self.make_success_test("Identifier Both Whitespace", " hello ",
"identifier", "hello")
self.make_success_test("Identifier Tab Before", "\thello",
self.make_success_test("Identifier Tab Before", "\\thello",
"identifier", "hello")
# Identifier literals with whitespace
@ -146,17 +150,13 @@ class IdentifierTestGenerator(BaseTestGenerator):
# Starting with number
self.make_error_test("Identifier Starting With Number",
"123abc",
"Invalid identifier: cannot start with digit.")
"Invalid decimal literal: unexpected 'a' in decimal integer.")
# Invalid characters
self.make_error_test("Identifier With Hash",
"my#var",
"Invalid identifier: '#' is not allowed in identifiers.")
self.make_error_test("Identifier With Dash",
"my-var",
"Invalid identifier: '-' is not allowed in identifiers.")
self.make_error_test("Identifier With Dot",
"my.var",
"Invalid identifier: '.' is not allowed in identifiers.")
@ -287,7 +287,7 @@ class BooleanTestGenerator(BaseTestGenerator):
"bool", True)
self.make_success_test("Bool True Both Whitespace", " true ",
"bool", True)
self.make_success_test("Bool True Tab Before", "\ttrue",
self.make_success_test("Bool True Tab Before", "\\ttrue",
"bool", True)
# False with whitespace
@ -297,73 +297,57 @@ class BooleanTestGenerator(BaseTestGenerator):
"bool", False)
self.make_success_test("Bool False Both Whitespace", " false ",
"bool", False)
self.make_success_test("Bool False Tab Before", "\tfalse",
self.make_success_test("Bool False Tab Before", "\\tfalse",
"bool", False)
def generate_error_tests(self):
"""Generate error test cases for booleans."""
# Capitalized (case sensitive)
self.make_error_test("Bool True Capitalized",
"True",
"Invalid boolean: 'True' is not a boolean literal (use lowercase 'true').")
self.make_success_test("Bool True Capitalized", "True",
"identifier", "True")
self.make_error_test("Bool False Capitalized",
"False",
"Invalid boolean: 'False' is not a boolean literal (use lowercase 'false').")
self.make_success_test("Bool False Capitalized", "False",
"identifier", "False")
# All caps
self.make_error_test("Bool True All Caps",
"TRUE",
"Invalid boolean: 'TRUE' is not a boolean literal (use lowercase 'true').")
self.make_success_test("Bool True All Caps", "TRUE",
"identifier", "TRUE")
self.make_error_test("Bool False All Caps",
"FALSE",
"Invalid boolean: 'FALSE' is not a boolean literal (use lowercase 'false').")
self.make_success_test("Bool False All Caps", "FALSE",
"identifier", "FALSE")
# Mixed case
self.make_error_test("Bool True Mixed Case",
"tRuE",
"Invalid boolean: 'tRuE' is not a boolean literal (use lowercase 'true').")
self.make_success_test("Bool True Mixed Case", "tRuE",
"identifier", "tRuE")
self.make_error_test("Bool False Mixed Case",
"fAlSe",
"Invalid boolean: 'fAlSe' is not a boolean literal (use lowercase 'false').")
self.make_success_test("Bool False Mixed Case", "fAlSe",
"identifier", "fAlSe")
# Numeric representations
self.make_error_test("Bool Numeric 1",
"1",
"Not a boolean: numeric literal.")
self.make_success_test("Bool Numeric 1", "1", "i64", 1)
self.make_error_test("Bool Numeric 0",
"0",
"Not a boolean: numeric literal.")
self.make_success_test("Bool Numeric 0", "0", "i64", 0)
# String representations
self.make_error_test("Bool String True",
'"true"',
"Not a boolean: string literal.")
self.make_success_test("Bool String True", '"true"',
"string", "true")
self.make_error_test("Bool String False",
'"false"',
"Not a boolean: string literal.")
self.make_success_test("Bool String False", '"false"',
"string", "false")
# Other languages
self.make_error_test("Bool Yes",
"yes",
"Invalid boolean: 'yes' is not a boolean literal.")
self.make_success_test("Bool Yes", "yes",
"identifier", "yes")
self.make_error_test("Bool No",
"no",
"Invalid boolean: 'no' is not a boolean literal.")
self.make_success_test("Bool No", "no",
"identifier", "no")
# Typos
self.make_error_test("Bool Typo Ture",
"ture",
"Invalid boolean: 'ture' is not a boolean literal.")
self.make_success_test("Bool Typo Ture", "ture",
"identifier", "ture")
self.make_error_test("Bool Typo Flase",
"flase",
"Invalid boolean: 'flase' is not a boolean literal.")
self.make_success_test("Bool Typo Flase", "flase",
"identifier", "flase")
def generate_multiple_bool_tests(self):
"""Generate tests with multiple boolean values."""