Skip to content

Commit 2c4fc9f

Browse files
authored
Merge pull request #158 from Brainrotlang/feat/stdrot
Brainrot standard library
2 parents 73134f6 + d361cc9 commit 2c4fc9f

22 files changed

Lines changed: 1204 additions & 644 deletions

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ jobs:
3636
uses: actions/upload-artifact@v4
3737
with:
3838
name: brainrot
39-
path: brainrot
39+
path: |
40+
brainrot
41+
libstdrot.so
4042
4143
test:
4244
runs-on: ubuntu-latest
@@ -50,10 +52,15 @@ jobs:
5052
uses: actions/download-artifact@v4
5153
with:
5254
name: brainrot
55+
path: .
5356

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

60+
- name: Prepare shared library for tests
61+
run: |
62+
cp -f libstdrot.so tests/libstdrot.so
63+
5764
- name: Install Python and dependencies
5865
run: |
5966
sudo apt-get update
@@ -66,6 +73,7 @@ jobs:
6673
- name: Run Pytest
6774
run: |
6875
source .venv/bin/activate
76+
export LD_LIBRARY_PATH="$PWD:$LD_LIBRARY_PATH"
6977
pytest -v test_brainrot.py
7078
working-directory: tests
7179

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ lang.tab.c
44
lang.tab.h
55
lex.yy.c
66
lang.gv
7+
libstdrot.so

Makefile

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,56 @@ PYTHON := python3
66

77
# Compiler and linker flags
88
CFLAGS := -Wall -Wextra -Wpedantic -Werror -O2 -Wuninitialized
9-
LDFLAGS := -lfl -lm
9+
LDFLAGS := -lfl -lm -ldl -rdynamic
10+
SO_CFLAGS := -fPIC -shared
1011

1112
# Source files and directories
1213
SRC_DIR := lib
1314
DEBUG_FLAGS := -g
14-
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
15+
SRCS := $(SRC_DIR)/hm.c $(SRC_DIR)/mem.c $(SRC_DIR)/arena.c ast.c visitor.c semantic_analyzer.c interpreter.c stdrot.c
1516
GENERATED_SRCS := lang.tab.c lex.yy.c
1617
ALL_SRCS := $(SRCS) $(GENERATED_SRCS)
1718

19+
# stdrot shared library
20+
STDROT_DIR := stdrot
21+
STDROT_SRCS := $(wildcard $(STDROT_DIR)/*.c) $(SRC_DIR)/input.c
22+
STDROT_LIB := libstdrot.so
23+
1824
# Output files
1925
TARGET := brainrot
2026
BISON_OUTPUT := lang.tab.c
2127
FLEX_OUTPUT := lex.yy.c
2228

2329
# Default target
2430
.PHONY: all
25-
all: $(TARGET)
31+
all: $(STDROT_LIB) $(TARGET)
32+
33+
# Ensure shared library exists for runtime targets
34+
.PHONY: ensure-stdrot
35+
ensure-stdrot:
36+
@if [ ! -f $(STDROT_LIB) ]; then \
37+
echo "$(STDROT_LIB) not found. Building it now..."; \
38+
$(MAKE) $(STDROT_LIB); \
39+
fi
40+
41+
# Build only the standard library
42+
.PHONY: lib
43+
lib: $(STDROT_LIB)
2644

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

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

3456
# Main executable build
35-
$(TARGET): $(ALL_SRCS)
36-
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
57+
$(TARGET): $(ALL_SRCS) $(STDROT_LIB)
58+
$(CC) $(CFLAGS) -o $@ $(ALL_SRCS) $(LDFLAGS)
3759
@echo "Skibidi toilet: $(TARGET) compiled with max gyatt."
3860

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

4971
# Run tests
5072
.PHONY: test
51-
test:
73+
test: ensure-stdrot $(TARGET)
5274
$(PYTHON) -m pytest -v
5375
@echo "Tests ran bussin', no cap."
5476

5577
# Clean build artifacts
5678
.PHONY: clean
5779
clean:
58-
rm -f $(TARGET) $(GENERATED_SRCS) lang.tab.h
80+
rm -f $(TARGET) $(STDROT_LIB) $(GENERATED_SRCS) lang.tab.h
5981
rm -f *.o
6082
@echo "Blud cleaned up the mess like a true sigma coder."
6183

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

6890
# Install target
6991
.PHONY: install
70-
install:
92+
install: ensure-stdrot $(TARGET)
7193
install -d /usr/local/bin
7294
install -m 755 $(TARGET) /usr/local/bin/
7395
@echo "$(TARGET) installed successfully. You're goated with the sauce!"

ast.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,6 @@ Scope *current_scope;
2828
/* Include the symbol table functions */
2929
extern void yyerror(const char *s);
3030
extern void cleanup(void);
31-
extern void ragequit(int exit_code);
32-
extern void chill(unsigned int seconds);
33-
extern void yapping(const char *format, ...);
34-
extern void yappin(const char *format, ...);
35-
extern void baka(const char *format, ...);
36-
extern char slorp_char(char chr);
37-
extern char *slorp_string(char *string, size_t size);
38-
extern int slorp_int(int val);
39-
extern short slorp_short(short val);
40-
extern float slorp_float(float var);
41-
extern double slorp_double(double var);
4231
extern TypeModifiers get_variable_modifiers(const char *name);
4332
extern int yylineno;
4433

@@ -553,7 +542,7 @@ static ASTNode *create_node(NodeType type, VarType var_type, TypeModifiers modif
553542
node->modifiers = modifiers;
554543
node->already_checked = false;
555544
node->is_valid_symbol = false;
556-
node->line_number = 0; /* Initialize line number to avoid uninitialized value errors */
545+
node->line_number = yylineno;
557546
return node;
558547
}
559548

@@ -2416,7 +2405,12 @@ void execute_statement(ASTNode *node)
24162405
case NODE_IDENTIFIER:
24172406
evaluate_expression(node);
24182407
break;
2419-
case NODE_FUNC_CALL:
2408+
case NODE_FUNC_CALL: {
2409+
// Set execution context with current line number
2410+
extern ExecutionContext g_exec_context;
2411+
g_exec_context.line_number = node->line_number;
2412+
g_exec_context.function_name = node->data.func_call.function_name;
2413+
24202414
// Use the stdrot built-in function system
24212415
if (is_builtin_function(node->data.func_call.function_name))
24222416
{
@@ -2429,6 +2423,7 @@ void execute_statement(ASTNode *node)
24292423
node->data.func_call.arguments);
24302424
}
24312425
break;
2426+
}
24322427
case NODE_FOR_STATEMENT:
24332428
execute_for_statement(node);
24342429
break;

docs/brainrot-user-guide.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ Brainrot includes some built-in functions for convenience:
204204
| **ragequit** | - | - | Terminates program execution immediately with the provided exit code. |
205205
| **chill** | - | - | Sleeps for an integer number of seconds. |
206206
| **slorp** | `stdin` | - | Reads user input. |
207+
| **bet** | `stderr` | No | Tests conditions and terminates with error message if false. |
207208

208209
## 9.1. yapping
209210

@@ -347,6 +348,49 @@ skibidi main {
347348
}
348349
```
349350

351+
## 9.7. bet
352+
353+
**Prototype**
354+
355+
```c
356+
void bet(int condition, const char* message);
357+
```
358+
359+
**Key Points**
360+
361+
- Tests a condition and terminates the program if it's false
362+
- Similar to C's `assert()` macro
363+
- When the condition fails, prints an error message with the line number and optional custom message
364+
- Useful for catching bugs and verifying assumptions during development
365+
366+
### Example
367+
368+
```c
369+
skibidi main {
370+
rizz x = 10;
371+
bet(x > 0, "x must be positive");
372+
yapping("x is positive");
373+
bussin 0;
374+
}
375+
```
376+
377+
### Failed Assertion Example
378+
379+
```c
380+
skibidi main {
381+
bet(L, "this assertion must fail");
382+
yapping("This won't print");
383+
bussin 0;
384+
}
385+
```
386+
387+
Output:
388+
```
389+
Error: bet: assertion failed at line 2: this assertion must fail
390+
```
391+
392+
The program terminates immediately when a `bet` fails.
393+
350394
---
351395

352396
# 10. Example Program

docs/the-brainrot-programming-language.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,46 @@ skibidi main {
409409
}
410410
```
411411

412+
### 8.7. `bet`
413+
414+
```c
415+
void bet(int condition, const char* message);
416+
```
417+
418+
- Tests a condition and terminates the program if it's false.
419+
- Similar to C's `assert()` macro, but designed for runtime checks in Brainrot.
420+
- When the condition fails, prints an error message to `stderr` with the line number and optional custom message.
421+
- Useful for verifying assumptions and catching bugs during development.
422+
423+
**Example**:
424+
425+
```c
426+
skibidi main {
427+
rizz x = 10;
428+
bet(x > 0, "x must be positive");
429+
yapping("x is positive");
430+
bussin 0;
431+
}
432+
```
433+
434+
**What happens when the assertion fails:**
435+
436+
```c
437+
skibidi main {
438+
bet(L, "this assertion must fail");
439+
yapping("This won't print");
440+
bussin 0;
441+
}
442+
```
443+
444+
Output:
445+
446+
```
447+
Error: bet: assertion failed at line 2: this assertion must fail
448+
```
449+
450+
The program terminates immediately when a `bet` fails, preventing further execution.
451+
412452
---
413453

414454
## 9. Limitations

interpreter.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88

99
extern void yyerror(const char *s);
1010
extern char *safe_strdup(const char *str);
11-
extern void yapping(const char* format, ...);
12-
extern void baka(const char* format, ...);
11+
extern void execute_func_call(const char *func_name, ArgumentList *args);
1312

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

648647
ASTNode *expr = node->data.op.left;
649-
if (expr->type == NODE_STRING_LITERAL) {
650-
yapping("%s", expr->data.strvalue);
651-
} else {
652-
int value = evaluate_expression_int(expr);
653-
yapping("%d", value);
654-
}
648+
ArgumentList args = {expr, NULL};
649+
execute_func_call("yapping", &args);
655650
}
656651

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

661656
ASTNode *expr = node->data.op.left;
662-
if (expr->type == NODE_STRING_LITERAL) {
663-
baka("%s", expr->data.strvalue);
664-
} else {
665-
int value = evaluate_expression_int(expr);
666-
baka("%d", value);
667-
}
657+
ArgumentList args = {expr, NULL};
658+
execute_func_call("baka", &args);
668659
}

0 commit comments

Comments
 (0)