Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: add more edge cases #42

Merged
merged 2 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 72 additions & 21 deletions ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <stdbool.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <limits.h>

static jmp_buf break_env;

Expand Down Expand Up @@ -258,24 +260,39 @@ float evaluate_expression_float(ASTNode *node)
case OP_TIMES:
return left * right;
case OP_DIVIDE:
if (right == 0.0f)
if (fabsf(right) < __FLT_MIN__)
{
yyerror("Division by zero");
return 0.0f;
if (fabsf(left) < __FLT_MIN__)
{
return 0.0f / 0.0f; // NaN
}
return left > 0 ? __FLT_MAX__ : -__FLT_MAX__;
}
return left / right;
case OP_LT:
return left < right ? 1.0f : 0.0f;
{
return (left - right) < -__FLT_EPSILON__ ? 1.0f : 0.0f;
}
case OP_GT:
return left > right ? 1.0f : 0.0f;
{
return (left - right) > __FLT_EPSILON__ ? 1.0f : 0.0f;
}
case OP_LE:
return left <= right ? 1.0f : 0.0f;
{
return (left - right) <= __FLT_EPSILON__ ? 1.0f : 0.0f;
}
case OP_GE:
return left >= right ? 1.0f : 0.0f;
{
return (left - right) >= -__FLT_EPSILON__ ? 1.0f : 0.0f;
}
case OP_EQ:
return left == right ? 1.0f : 0.0f;
{
return fabsf(left - right) <= __FLT_EPSILON__ ? 1.0f : 0.0f;
}
case OP_NE:
return left != right ? 1.0f : 0.0f;
{
return fabsf(left - right) > __FLT_EPSILON__ ? 1.0f : 0.0f;
}
default:
yyerror("Invalid operator for float operation");
return 0.0f;
Expand All @@ -302,7 +319,7 @@ float evaluate_expression_float(ASTNode *node)
double evaluate_expression_double(ASTNode *node)
{
if (!node)
return 0.0f;
return 0.0L;

switch (node->type)
{
Expand Down Expand Up @@ -334,7 +351,7 @@ double evaluate_expression_double(ASTNode *node)
}
}
yyerror("Undefined variable");
return 0.0f;
return 0.0L;
}
case NODE_OPERATION:
{
Expand All @@ -350,24 +367,39 @@ double evaluate_expression_double(ASTNode *node)
case OP_TIMES:
return left * right;
case OP_DIVIDE:
if (right == 0.0L)
if (fabs(right) < __DBL_MIN__)
{
yyerror("Division by zero");
return 0.0L;
if (fabs(left) < __DBL_MIN__)
{
return 0.0 / 0.0; // NaN
}
return left > 0 ? __DBL_MAX__ : -__DBL_MAX__;
}
return left / right;
case OP_LT:
return left < right ? 1.0L : 0.0L;
{
return (left - right) < -__FLT_EPSILON__ ? 1.0L : 0.0L;
}
case OP_GT:
return left > right ? 1.0L : 0.0L;
{
return (left - right) > __DBL_EPSILON__ ? 1.0L : 0.0L;
}
case OP_LE:
return left <= right ? 1.0L : 0.0L;
{
return (left - right) <= __DBL_EPSILON__ ? 1.0L : 0.0L;
}
case OP_GE:
return left >= right ? 1.0L : 0.0L;
{
return (left - right) >= -__DBL_EPSILON__ ? 1.0L : 0.0L;
}
case OP_EQ:
return left == right ? 1.0L : 0.0L;
{
return fabs(left - right) <= __DBL_EPSILON__ ? 1.0L : 0.0L;
}
case OP_NE:
return left != right ? 1.0L : 0.0L;
{
return fabs(left - right) > __DBL_EPSILON__ ? 1.0L : 0.0L;
}
default:
yyerror("Invalid operator for double operation");
return 0.0L;
Expand Down Expand Up @@ -825,7 +857,26 @@ void execute_assignment(ASTNode *node)
ASTNode *value_node = node->data.op.right;
TypeModifiers mods = node->modifiers;

// Check if the right-hand side is a float expression
// Handle type conversion for float to int
if (value_node->type == NODE_FLOAT || is_float_expression(value_node))
{
float value = evaluate_expression_float(value_node);
if (node->data.op.left->type == NODE_INT)
{
// Check for overflow
if (value > INT_MAX || value < INT_MIN)
{
yyerror("Float to int conversion overflow");
value = INT_MAX;
}
if (!set_int_variable(name, (int)value, mods))
{
yyerror("Failed to set integer variable");
}
return;
}
}

if (is_float_expression(value_node))
{
float value = evaluate_expression_float(value_node);
Expand Down
11 changes: 11 additions & 0 deletions examples/comparison_edge_case.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
skibidi main {
chad epsilon = 1.0e-6;
chad a = 1.0;
chad b = 0.9999999;
edgy (a - b < epsilon) {
yappin("%d\n", W); 🚽 Should output: 1
} amogus {
yappin("%d\n", L);
}
bussin 0;
}
10 changes: 10 additions & 0 deletions examples/division_edge_cases.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
skibidi main {
chad f = 0.0;
gigachad d = 0.0;
rizz i = 0;
yappin("%f\n", 1.0 / f); 🚽 Should output: inf
yappin("%f\n", f / f); 🚽 Should output: nan
yappin("%f\n", d / 0.0); 🚽 Should output: inf
yapping("%d\n", 1 / i); 🚽 Should output: Error: Division by zero
bussin 0;
}
11 changes: 11 additions & 0 deletions examples/double_vs_float.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
🚽 TODO: disabled test. returns 1.0 instead of 0.0. Needs further investigation.
skibidi main {
chad f = 1.0e8;
gigachad d = 1.0e8;
chad f1 = f + 1.0;
gigachad d1 = d + 1.0;
yappin("%.1f %.1f\n", f1 - f, d1 - d);
🚽 Should output: 0.0 1.0
🚽 (float loses precision, double maintains it)
bussin 0;
}
7 changes: 7 additions & 0 deletions examples/float_precision.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
skibidi main {
chad tiny = 1.175494351e-38; 🚽 FLT_MIN
chad big = 3.402823466e+38; 🚽 FLT_MAX
chad sum = big + tiny;
yappin("%f\n", sum - big); 🚽 Should output: 0.000000 (precision loss)
bussin 0;
}
7 changes: 7 additions & 0 deletions examples/integer_overflow.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
skibidi main {
rizz max = 2147483647; 🚽 INT_MAX
rizz min = -2147483648; 🚽 INT_MIN
yappin("%d\n", max + 1); 🚽 Should output: -2147483648 (overflow)
yappin("%d\n", min - 1); 🚽 Should output: 2147483647 (underflow)
bussin 0;
}
9 changes: 9 additions & 0 deletions examples/mixed_types.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
skibidi main {
chad f = 3.14;
gigachad d = 3.14;
rizz i = 42;
nonut rizz u = 42;
yappin("%f\n", f * i); 🚽 Should output: 131.880000
yappin("%f\n", d * u); 🚽 Should output: 131.880000
bussin 0;
}
9 changes: 9 additions & 0 deletions examples/modulo_edge_case.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
skibidi main {
rizz a = -5;
rizz b = 3;
yappin("%d\n", a % b); 🚽 Should output: -2
nonut rizz x = 5;
nonut rizz y = 3;
yappin("%u\n", x % y); 🚽 Should output: 2
bussin 0;
}
7 changes: 7 additions & 0 deletions examples/scientific_notation.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
skibidi main {
chad f = 1.23e-7;
gigachad d = 1.23e-15;
yappin("%e\n", f); 🚽 Should output: 1.230000e-07
yappin("%e\n", d); 🚽 Should output: 1.230000e-15
bussin 0;
}
8 changes: 8 additions & 0 deletions examples/type_conversion.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
skibidi main {
chad huge_float = 3.4e38;
rizz converted = huge_float; 🚽 Should be INT_MAX or error
gigachad precise = 123456789.123456789;
chad less_precise = precise; 🚽 Precision loss
yappin("%f\n", less_precise); 🚽 Should output: 123456789.000000
bussin 0;
}
6 changes: 6 additions & 0 deletions examples/unsigned_integer_wrap.brainrot
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
skibidi main {
nonut rizz big = 4294967295; 🚽 UINT_MAX
yappin("%u\n", big + 1); 🚽 Should output: 0 (wrap around)
yappin("%u\n", big * 2); 🚽 Should output: 4294967294 (wrap around)
bussin 0;
}
14 changes: 5 additions & 9 deletions lang.l
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,13 @@ extern int yylineno;
"🚽"[^\n]* ; /* Ignore single line comments */
"W" { yylval.ival = 1; return BOOLEAN; }
"L" { yylval.ival = 0; return BOOLEAN; }
[0-9]+\.[0-9]+[fF]? {
if (yytext[strlen(yytext) - 1] == 'f' || yytext[strlen(yytext) - 1] == 'F') {
// 'f' or 'F' suffix: float literal
char *buffer = strdup(yytext);
buffer[strlen(buffer) - 1] = '\0'; // Remove the 'f' suffix
yylval.fval = atof(buffer); // Convert to float
free(buffer);
[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[fF]? {
char *endptr;
if (strchr(yytext, 'f') || strchr(yytext, 'F')) {
yylval.fval = strtof(yytext, &endptr);
return FLOAT_LITERAL;
} else {
// No suffix: double literal
yylval.dval = strtod(yytext, NULL); // Convert to double
yylval.dval = strtod(yytext, &endptr);
return DOUBLE_LITERAL;
}
}
Expand Down
39 changes: 24 additions & 15 deletions tests/expected_results.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
{
"boolean.brainrot": "It's valid!\nL\nW\n",
"fizz_buzz.brainrot": "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n",
"hello_world.brainrot": "Hello, World!\n",
"sizeof.brainrot": "4\n4\n1\n",
"char.brainrot": "c\n",
"float.brainrot": "3.141592\n",
"modulo.brainrot": "2\n",
"switch_case.brainrot": "You chose 2, gigachad move!\n",
"circle_area.brainrot": "78.540\n",
"circle_area_double.brainrot": "78.539800\n",
"for_loop.brainrot": "Skibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\n",
"output_error.brainrot": "you sussy baka!",
"while_loop.brainrot": "AAAAAH A GOONIN LOOP\n1\nAAAAAH A GOONIN LOOP\n2\nAAAAAH A GOONIN LOOP\n3\nAAAAAH A GOONIN LOOP\n4\n",
"int.brainrot": "10\n5\n3\n-3\n20\n-20\n2\n1\n2\n-2",
"uint.brainrot": "10\n9931737\n3\n647238965\n20\n245413032\n2\n1\n2\n1"
"comparison_edge_case": "1\n",
"division_edge_cases": "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000\n-nan\n-nan\n0",
"float_precision": "0.000000\n",
"integer_overflow": "-2147483648\n2147483647\n",
"mixed_types": "131.880000\n131.880000\n",
"modulo_edge_case": "-2\n2\n",
"scientific_notation": "1.230000e-07\n1.230000e-15\n",
"type_conversion": "123456789.123457\n",
"unsigned_integer_wrap": "0\n4294967294\n",
"boolean": "It's valid!\nL\nW\n",
"fizz_buzz": "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n",
"hello_world": "Hello, World!\n",
"sizeof": "4\n4\n1\n",
"char": "c\n",
"float": "3.141592\n",
"modulo": "2\n",
"switch_case": "You chose 2, gigachad move!\n",
"circle_area": "78.540\n",
"circle_area_double": "78.539800\n",
"for_loop": "Skibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\n",
"output_error": "you sussy baka!",
"while_loop": "AAAAAH A GOONIN LOOP\n1\nAAAAAH A GOONIN LOOP\n2\nAAAAAH A GOONIN LOOP\n3\nAAAAAH A GOONIN LOOP\n4\n",
"int": "10\n5\n3\n-3\n20\n-20\n2\n1\n2\n-2",
"uint": "10\n9931737\n3\n647238965\n20\n245413032\n2\n1\n2\n1"
}
2 changes: 1 addition & 1 deletion tests/test_brainrot.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
def test_brainrot_examples(example, expected_output):
# Construct absolute paths for the brainrot executable and example file
brainrot_path = os.path.abspath(os.path.join(script_dir, "../brainrot"))
example_file_path = os.path.abspath(os.path.join(script_dir, f"../examples/{example}"))
example_file_path = os.path.abspath(os.path.join(script_dir, f"../examples/{example}.brainrot"))

# Define the command to execute
command = f"{brainrot_path} < {example_file_path}"
Expand Down
Loading