diff --git a/ast.c b/ast.c index d7fddb2..1f12345 100644 --- a/ast.c +++ b/ast.c @@ -60,6 +60,12 @@ bool set_int_variable(const char *name, int value, TypeModifiers mods) return set_variable(name, &value, VAR_INT, mods); } +bool set_char_variable(const char *name, int value, TypeModifiers mods) +{ + return set_variable(name, &value, VAR_CHAR, mods); +} + + bool set_array_variable(char *name, int length, TypeModifiers mods, VarType type) { // search for an existing variable @@ -153,7 +159,7 @@ extern void yapping(const char *format, ...); extern void yappin(const char *format, ...); extern void baka(const char *format, ...); extern char slorp_char(char chr); -extern char *slorp_string(char *string); +extern char *slorp_string(char *string, size_t size); extern int slorp_int(int val); extern short slorp_short(short val); extern float slorp_float(float var); @@ -2228,7 +2234,7 @@ void execute_statement(ASTNode *node) if (value_node->type == NODE_CHAR) { // Handle character assignments directly - if (!set_int_variable(name, value_node->data.ivalue, mods)) + if (!set_char_variable(name, value_node->data.ivalue, mods)) { yyerror("Failed to set character variable"); } @@ -2710,12 +2716,23 @@ void execute_yapping_call(ArgumentList *args) else if (*format == 's') { // String - if (expr->type != NODE_STRING_LITERAL) + const Variable *var = get_variable(expr->data.name); + if (var != NULL) + { + if (!var->is_array) + { + yyerror("Invalid argument type for %s"); + exit(EXIT_FAILURE); + } + buffer_offset += snprintf(buffer + buffer_offset, sizeof(buffer) - buffer_offset, specifier, var->value.carray); + } + else if (expr->type != NODE_STRING_LITERAL) { yyerror("Invalid argument type for %s"); exit(EXIT_FAILURE); + }else{ + buffer_offset += snprintf(buffer + buffer_offset, sizeof(buffer) - buffer_offset, specifier, expr->data.name); } - buffer_offset += snprintf(buffer + buffer_offset, sizeof(buffer) - buffer_offset, specifier, expr->data.name); } else { @@ -2847,13 +2864,23 @@ void execute_yappin_call(ArgumentList *args) } else if (*format == 's') { - // Handle string literals - if (expr->type != NODE_STRING_LITERAL) + const Variable *var = get_variable(expr->data.name); + if (var != NULL) + { + if (!var->is_array) + { + yyerror("Invalid argument type for %s"); + exit(EXIT_FAILURE); + } + buffer_offset += snprintf(buffer + buffer_offset, sizeof(buffer) - buffer_offset, specifier, var->value.carray); + } + else if (expr->type != NODE_STRING_LITERAL) { yyerror("Invalid argument type for %s"); exit(EXIT_FAILURE); + }else{ + buffer_offset += snprintf(buffer + buffer_offset, sizeof(buffer) - buffer_offset, specifier, expr->data.name); } - buffer_offset += snprintf(buffer + buffer_offset, sizeof(buffer) - buffer_offset, specifier, expr->data.name); } else { @@ -2986,6 +3013,13 @@ void execute_slorp_call(ArgumentList *args) } case VAR_CHAR: { + if (var->is_array) + { + char val[var->array_length]; + slorp_string(val, sizeof(val)); + var->value.carray = safe_strdup(val); + return; + } char val = 0; val = slorp_char(val); set_int_variable(name, val, var->modifiers); @@ -3354,6 +3388,7 @@ void free_ast(ASTNode *node) case NODE_FLOAT: case NODE_DOUBLE: case NODE_BOOLEAN: + case NODE_CHAR: // These nodes don't have additional allocations break; diff --git a/lang.y b/lang.y index 8d09b50..60adeea 100644 --- a/lang.y +++ b/lang.y @@ -18,7 +18,7 @@ void yapping(const char* format, ...); void yappin(const char* format, ...); void baka(const char* format, ...); char slorp_char(char chr); -char *slorp_string(char *string); +char *slorp_string(char *string, size_t size); int slorp_int(int val); short slorp_short(short val); float slorp_float(float var); @@ -576,11 +576,11 @@ char slorp_char(char chr) { } } -char *slorp_string(char *string) { +char *slorp_string(char *string, size_t size) { size_t chars_read; input_status status; - status = input_string(string, sizeof(string), &chars_read); + status = input_string(string, size, &chars_read); if (status == INPUT_SUCCESS) { return string; @@ -608,6 +608,7 @@ int slorp_int(int val) { else if (status == INPUT_INTEGER_OVERFLOW) { fprintf(stderr, "Error: Integer value out of range.\n"); + exit(EXIT_FAILURE); } else if (status == INPUT_CONVERSION_ERROR) { @@ -633,6 +634,7 @@ short slorp_short(short val) { else if (status == INPUT_SHORT_OVERFLOW) { fprintf(stderr, "Error: short value out of range.\n"); + exit(EXIT_FAILURE); } else if (status == INPUT_CONVERSION_ERROR) { diff --git a/lib/input.c b/lib/input.c index dd00f3b..8af85f1 100644 --- a/lib/input.c +++ b/lib/input.c @@ -63,7 +63,7 @@ input_status input_string(char *buffer, size_t buffer_size, size_t *chars_read) return INPUT_NULL_PTR; } - if (buffer_size == 0) + if (buffer_size <= 1) { return INPUT_BUFFER_OVERFLOW; } @@ -87,9 +87,8 @@ input_status input_string(char *buffer, size_t buffer_size, size_t *chars_read) // Check if the input was truncated (no newline found) size_t len = strnlen(buffer, buffer_size); - if (len == buffer_size - 1 && buffer[len - 1] != '\n') + if(len == buffer_size && buffer[len - 1] != '\n') { - // Input was truncated; clear the remaining input clear_stdin_buffer(); return INPUT_BUFFER_OVERFLOW; } diff --git a/run_valgrind_tests.sh b/run_valgrind_tests.sh index 33911ce..f68866d 100755 --- a/run_valgrind_tests.sh +++ b/run_valgrind_tests.sh @@ -2,6 +2,10 @@ for f in test_cases/*.brainrot; do echo "Running Valgrind on $f..." - valgrind --leak-check=full --error-exitcode=1 ./brainrot "$f" + if [[ $(basename "$f") == slorp_int* ]]; then + echo "42" | valgrind --leak-check=full --error-exitcode=1 ./brainrot "$f" + else + valgrind --leak-check=full --error-exitcode=1 ./brainrot "$f" + fi echo done \ No newline at end of file diff --git a/test_cases/slorp_char.brainrot b/test_cases/slorp_char.brainrot new file mode 100644 index 0000000..bb14347 --- /dev/null +++ b/test_cases/slorp_char.brainrot @@ -0,0 +1,6 @@ +skibidi main { + yap chr; + slorp(chr); + yapping("You typed: %c", chr); + bussin 0; +} diff --git a/test_cases/slorp_double.brainrot b/test_cases/slorp_double.brainrot new file mode 100644 index 0000000..a0cf581 --- /dev/null +++ b/test_cases/slorp_double.brainrot @@ -0,0 +1,6 @@ +skibidi main { + gigachad num; + slorp(num); + yapping("You typed: %f", num); + bussin 0; +} diff --git a/test_cases/slorp_float.brainrot b/test_cases/slorp_float.brainrot new file mode 100644 index 0000000..6b26793 --- /dev/null +++ b/test_cases/slorp_float.brainrot @@ -0,0 +1,6 @@ +skibidi main { + chad num; + slorp(num); + yapping("You typed: %f", num); + bussin 0; +} diff --git a/test_cases/slorp_int.brainrot b/test_cases/slorp_int.brainrot new file mode 100644 index 0000000..304b1c2 --- /dev/null +++ b/test_cases/slorp_int.brainrot @@ -0,0 +1,6 @@ +skibidi main { + rizz num; + slorp(num); + yapping("You typed: %d", num); + bussin 0; +} diff --git a/test_cases/slorp_short.brainrot b/test_cases/slorp_short.brainrot new file mode 100644 index 0000000..6593d83 --- /dev/null +++ b/test_cases/slorp_short.brainrot @@ -0,0 +1,6 @@ +skibidi main { + smol num; + slorp(num); + yapping("You typed: %d", num); + bussin 0; +} diff --git a/test_cases/slorp_string.brainrot b/test_cases/slorp_string.brainrot new file mode 100644 index 0000000..c6fad07 --- /dev/null +++ b/test_cases/slorp_string.brainrot @@ -0,0 +1,6 @@ +skibidi main { + yap string[32]; + slorp(string); + yapping("You typed: %s", string); + bussin 0; +} diff --git a/tests/expected_results.json b/tests/expected_results.json index 31d1a6c..4bc6063 100644 --- a/tests/expected_results.json +++ b/tests/expected_results.json @@ -42,5 +42,11 @@ "add_two_numbers": "3", "mul_two_numbers": "11.400000", "max_gigachad": "5.000000", - "is_prime": "W" + "is_prime": "W", + "slorp_int": "You typed: 42", + "slorp_short": "You typed: 69", + "slorp_float": "You typed: 3.140000", + "slorp_double": "You typed: 3.141592", + "slorp_char": "You typed: c", + "slorp_string": "You typed: skibidi bop bop yes yes" } diff --git a/tests/test_brainrot.py b/tests/test_brainrot.py index 6f9a961..e4b9d67 100644 --- a/tests/test_brainrot.py +++ b/tests/test_brainrot.py @@ -17,24 +17,34 @@ def test_brainrot_examples(example, expected_output): brainrot_path = os.path.abspath(os.path.join(script_dir, "../brainrot")) example_file_path = os.path.abspath(os.path.join(script_dir, f"../test_cases/{example}.brainrot")) - command = f"{brainrot_path} {example_file_path}" - + + if example.startswith("slorp_int"): + command = f"echo '42' | {brainrot_path} {example_file_path}" + elif example.startswith("slorp_short"): + command = f"echo '69' | {brainrot_path} {example_file_path}" + elif example.startswith("slorp_float"): + command = f"echo '3.14' | {brainrot_path} {example_file_path}" + elif example.startswith("slorp_double"): + command = f"echo '3.141592' | {brainrot_path} {example_file_path}" + elif example.startswith("slorp_char"): + command = f"echo 'c' | {brainrot_path} {example_file_path}" + elif example.startswith("slorp_string"): + command = f"echo 'skibidi bop bop yes yes' | {brainrot_path} {example_file_path}" + else: + command = f"{brainrot_path} {example_file_path}" + result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True) - - # Go back to original logic - only use stderr if stdout is empty actual_output = result.stdout.strip() if result.stdout.strip() else result.stderr.strip() - - # Special case: if output contains "Stderr:", we need both + if "Stderr:" in expected_output and result.stdout.strip(): actual_output = f"{result.stdout.strip()}\nStderr:\n{result.stderr.strip()}" - + assert actual_output == expected_output.strip(), ( f"Output for {example} did not match.\n" f"Expected:\n{expected_output}\n" f"Actual:\n{actual_output}" ) - - # Only check return code for non-error cases + if "Error:" not in expected_output: assert result.returncode == 0, ( f"Command for {example} failed with return code {result.returncode}\n"