Skip to content
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
10 changes: 9 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: brainrot
path: brainrot
path: |
brainrot
libstdrot.so

test:
runs-on: ubuntu-latest
Expand All @@ -50,10 +52,15 @@ jobs:
uses: actions/download-artifact@v4
with:
name: brainrot
path: .

- name: Grant execute permissions to Brainrot
run: chmod +x brainrot

- name: Prepare shared library for tests
run: |
cp -f libstdrot.so tests/libstdrot.so

- name: Install Python and dependencies
run: |
sudo apt-get update
Expand All @@ -66,6 +73,7 @@ jobs:
- name: Run Pytest
run: |
source .venv/bin/activate
export LD_LIBRARY_PATH="$PWD:$LD_LIBRARY_PATH"
pytest -v test_brainrot.py
working-directory: tests

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ lang.tab.c
lang.tab.h
lex.yy.c
lang.gv
libstdrot.so
42 changes: 32 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,56 @@ PYTHON := python3

# Compiler and linker flags
CFLAGS := -Wall -Wextra -Wpedantic -Werror -O2 -Wuninitialized
LDFLAGS := -lfl -lm
LDFLAGS := -lfl -lm -ldl -rdynamic
SO_CFLAGS := -fPIC -shared

# Source files and directories
SRC_DIR := lib
DEBUG_FLAGS := -g
SRCS := $(SRC_DIR)/hm.c $(SRC_DIR)/mem.c $(SRC_DIR)/input.c $(SRC_DIR)/arena.c ast.c visitor.c semantic_analyzer.c interpreter.c stdrot.c
SRCS := $(SRC_DIR)/hm.c $(SRC_DIR)/mem.c $(SRC_DIR)/arena.c ast.c visitor.c semantic_analyzer.c interpreter.c stdrot.c
GENERATED_SRCS := lang.tab.c lex.yy.c
ALL_SRCS := $(SRCS) $(GENERATED_SRCS)

# stdrot shared library
STDROT_DIR := stdrot
STDROT_SRCS := $(wildcard $(STDROT_DIR)/*.c) $(SRC_DIR)/input.c
STDROT_LIB := libstdrot.so

# Output files
TARGET := brainrot
BISON_OUTPUT := lang.tab.c
FLEX_OUTPUT := lex.yy.c

# Default target
.PHONY: all
all: $(TARGET)
all: $(STDROT_LIB) $(TARGET)

# Ensure shared library exists for runtime targets
.PHONY: ensure-stdrot
ensure-stdrot:
@if [ ! -f $(STDROT_LIB) ]; then \
echo "$(STDROT_LIB) not found. Building it now..."; \
$(MAKE) $(STDROT_LIB); \
fi

# Build only the standard library
.PHONY: lib
lib: $(STDROT_LIB)

# Debug target
.PHONY: debug
debug: CFLAGS += $(DEBUG_FLAGS)
debug: clean $(TARGET)
debug: clean all
@echo "Debug build compiled with -g. Time to sigma grind with GDB."

# stdrot shared library build
$(STDROT_LIB): $(STDROT_SRCS)
$(CC) $(SO_CFLAGS) -I. -o $@ $^ -lm
@echo "libstdrot.so compiled with max rizz."

# Main executable build
$(TARGET): $(ALL_SRCS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
$(TARGET): $(ALL_SRCS) $(STDROT_LIB)
$(CC) $(CFLAGS) -o $@ $(ALL_SRCS) $(LDFLAGS)
@echo "Skibidi toilet: $(TARGET) compiled with max gyatt."

# Generate parser files using Bison
Expand All @@ -48,26 +70,26 @@ $(FLEX_OUTPUT): lang.l

# Run tests
.PHONY: test
test:
test: ensure-stdrot $(TARGET)
$(PYTHON) -m pytest -v
@echo "Tests ran bussin', no cap."

# Clean build artifacts
.PHONY: clean
clean:
rm -f $(TARGET) $(GENERATED_SRCS) lang.tab.h
rm -f $(TARGET) $(STDROT_LIB) $(GENERATED_SRCS) lang.tab.h
rm -f *.o
@echo "Blud cleaned up the mess like a true sigma coder."

# Run Valgrind on all .brainrot tests
.PHONY: valgrind
valgrind:
valgrind: ensure-stdrot $(TARGET)
@./run_valgrind_tests.sh
@echo "Valgrind check done. If anything was sus, it'll show up with a non-zero exit code. No cap."

# Install target
.PHONY: install
install:
install: ensure-stdrot $(TARGET)
install -d /usr/local/bin
install -m 755 $(TARGET) /usr/local/bin/
@echo "$(TARGET) installed successfully. You're goated with the sauce!"
Expand Down
21 changes: 8 additions & 13 deletions ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,6 @@ Scope *current_scope;
/* Include the symbol table functions */
extern void yyerror(const char *s);
extern void cleanup(void);
extern void ragequit(int exit_code);
extern void chill(unsigned int seconds);
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, size_t size);
extern int slorp_int(int val);
extern short slorp_short(short val);
extern float slorp_float(float var);
extern double slorp_double(double var);
extern TypeModifiers get_variable_modifiers(const char *name);
extern int yylineno;

Expand Down Expand Up @@ -553,7 +542,7 @@ static ASTNode *create_node(NodeType type, VarType var_type, TypeModifiers modif
node->modifiers = modifiers;
node->already_checked = false;
node->is_valid_symbol = false;
node->line_number = 0; /* Initialize line number to avoid uninitialized value errors */
node->line_number = yylineno;
return node;
}

Expand Down Expand Up @@ -2416,7 +2405,12 @@ void execute_statement(ASTNode *node)
case NODE_IDENTIFIER:
evaluate_expression(node);
break;
case NODE_FUNC_CALL:
case NODE_FUNC_CALL: {
// Set execution context with current line number
extern ExecutionContext g_exec_context;
g_exec_context.line_number = node->line_number;
g_exec_context.function_name = node->data.func_call.function_name;

// Use the stdrot built-in function system
if (is_builtin_function(node->data.func_call.function_name))
{
Expand All @@ -2429,6 +2423,7 @@ void execute_statement(ASTNode *node)
node->data.func_call.arguments);
}
break;
}
case NODE_FOR_STATEMENT:
execute_for_statement(node);
break;
Expand Down
44 changes: 44 additions & 0 deletions docs/brainrot-user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ Brainrot includes some built-in functions for convenience:
| **ragequit** | - | - | Terminates program execution immediately with the provided exit code. |
| **chill** | - | - | Sleeps for an integer number of seconds. |
| **slorp** | `stdin` | - | Reads user input. |
| **bet** | `stderr` | No | Tests conditions and terminates with error message if false. |

## 9.1. yapping

Expand Down Expand Up @@ -347,6 +348,49 @@ skibidi main {
}
```

## 9.7. bet

**Prototype**

```c
void bet(int condition, const char* message);
```

**Key Points**

- Tests a condition and terminates the program if it's false
- Similar to C's `assert()` macro
- When the condition fails, prints an error message with the line number and optional custom message
- Useful for catching bugs and verifying assumptions during development

### Example

```c
skibidi main {
rizz x = 10;
bet(x > 0, "x must be positive");
yapping("x is positive");
bussin 0;
}
```

### Failed Assertion Example

```c
skibidi main {
bet(L, "this assertion must fail");
yapping("This won't print");
bussin 0;
}
```

Output:
```
Error: bet: assertion failed at line 2: this assertion must fail
```

The program terminates immediately when a `bet` fails.

---

# 10. Example Program
Expand Down
40 changes: 40 additions & 0 deletions docs/the-brainrot-programming-language.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,46 @@ skibidi main {
}
```

### 8.7. `bet`

```c
void bet(int condition, const char* message);
```

- Tests a condition and terminates the program if it's false.
- Similar to C's `assert()` macro, but designed for runtime checks in Brainrot.
- When the condition fails, prints an error message to `stderr` with the line number and optional custom message.
- Useful for verifying assumptions and catching bugs during development.

**Example**:

```c
skibidi main {
rizz x = 10;
bet(x > 0, "x must be positive");
yapping("x is positive");
bussin 0;
}
```

**What happens when the assertion fails:**

```c
skibidi main {
bet(L, "this assertion must fail");
yapping("This won't print");
bussin 0;
}
```

Output:

```
Error: bet: assertion failed at line 2: this assertion must fail
```

The program terminates immediately when a `bet` fails, preventing further execution.

---

## 9. Limitations
Expand Down
19 changes: 5 additions & 14 deletions interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

extern void yyerror(const char *s);
extern char *safe_strdup(const char *str);
extern void yapping(const char* format, ...);
extern void baka(const char* format, ...);
extern void execute_func_call(const char *func_name, ArgumentList *args);

/* External functions we need from the original implementation */
extern Variable *variable_new(char *name);
Expand Down Expand Up @@ -646,23 +645,15 @@ void interpreter_visit_print_statement(Visitor *self, ASTNode *node) {
if (!node || !node->data.op.left) return;

ASTNode *expr = node->data.op.left;
if (expr->type == NODE_STRING_LITERAL) {
yapping("%s", expr->data.strvalue);
} else {
int value = evaluate_expression_int(expr);
yapping("%d", value);
}
ArgumentList args = {expr, NULL};
execute_func_call("yapping", &args);
}

void interpreter_visit_error_statement(Visitor *self, ASTNode *node) {
(void)self;
if (!node || !node->data.op.left) return;

ASTNode *expr = node->data.op.left;
if (expr->type == NODE_STRING_LITERAL) {
baka("%s", expr->data.strvalue);
} else {
int value = evaluate_expression_int(expr);
baka("%d", value);
}
ArgumentList args = {expr, NULL};
execute_func_call("baka", &args);
}
Loading