# Brainrot: a C-like language with the keywords replaced by slang

> Brainrot is a GPL-3.0 meme programming language built with Flex and Bison, where void becomes skibidi and int becomes rizz, and where the standard library and a real raylib game loop sit behind a compiler toolchain that regenerates the lexer and parser on every build. It is an interpreter with a serious build system, and the interesting parts are the module system and the generated FFI binding rather than the joke.

**Brainrotlang/brainrot** — Brainrot programming language interpreter

- Repository: https://github.com/Brainrotlang/brainrot
- Website: https://brainrotlang.com/
- Stars: 629 · Forks: 48
- Language: C
- License: GPL-3.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/brainrotlang-brainrot

## A keyword table on top of a real compiler pipeline

Brainrot is described in the README as a meme-inspired programming language that translates common programming keywords into internet slang and meme references, and the stated purpose is to make it a fun way to learn about language processing and compiler design. The keyword mapping is the joke and it is a complete one. void becomes skibidi, int becomes rizz, for becomes flex, return becomes bussin, and the reference table extends the conceit through cap for bool, edgy for if, amogus for else, goon for while, bruh for break, grind for continue, chad for float, gigachad for double, yap for char, deadass for const, sigma rule for case, based for default, mewing for do, gyatt for enum, giga for long, smol for short, nut for signed, maxxing for sizeof, salty for static, gang for struct, ohio for switch, chungus for union, nonut for unsigned and schizo for volatile, with W and L standing in for true and false.

The important observation is that nothing about the implementation changes. The language is C-like, the grammar is the same, and the transformation happens entirely in the keyword table, which is why the project can be a genuine interpreter rather than a text filter. The interpreter is written in C, the primary language of the repository, with the source split into ast.c, interpreter.c, semantic_analyzer.c and visitor.c alongside their headers, the Flex scanner in lang.l, the Bison grammar in lang.y, and the standard library in stdrot.c plus the stdrot/ directory. The licence is GPL-3.0 and the default branch is main.

## Flex, Bison and a make that regenerates the parser

The build is where this stops being a toy. Building from source needs a C compiler, either GCC or Clang, plus Flex, Bison, and the OpenSSL development headers, and the reason for OpenSSL is spelled out in the README: the standard library's gamba() CSPRNG links libcrypto.

```bash
git clone https://github.com/Brainrotlang/brainrot.git
cd brainrot
make                       # regenerates the lexer/parser, builds ./brainrot + libstdrot.so
./brainrot examples/hello_world.brainrot
sudo make install          # optional: install under /usr/local
```

The Makefile shows what the flags mean in practice. The CFLAGS are -Wall -Wextra -Wpedantic -Werror -O2 -Wuninitialized with the address and undefined behaviour sanitizers switched on, plus -fno-omit-frame-pointer and debug symbols, and the linker pulls in -lfl -lm -ldl -rdynamic, which is the Flex library, the maths library and the dynamic loader. The shared library libstdrot.so is built with -fPIC -shared and its own warning gate, and the comment explains why -Wpedantic is excluded there: gcc rejects STDROT_EXPORT_SIG's static initializer as not constant while clang-15 and emcc accept it, so the WebAssembly job is the one that covers that code with the compiler that agrees with the standard.

The sanitizers are on for ordinary development, and there is a separate Valgrind path, with the CFLAGS filtered to drop the sanitizers for it, because ASan's shadow map and valgrind do not coexist everywhere. The README is also clear that make regenerates the lexer and parser, so a build is never just a compile.

## Writing a program, and the module system behind #cooked

A Brainrot source file uses the slang keywords, and the hello world example in the README shows the shape.

```c
 skibidi main {
    yapping("Hello, World!");
    bussin 0;
}
```

```bash
./brainrot hello.brainrot
```

The examples directory shows the range the language is meant to cover, and it is wider than a joke: hello world, Fizz Buzz, Bubble Sort, a one-dimensional heat equation solver, Fibonacci, string parsing, a file word count, a sieve of Eratosthenes, a twoSum, mathutils, an array of structs and a string toolkit. Modules come in two forms, plain modules with #cooked and named modules with #cooked <name>, and the README also notes that a TRUTH.md file holds what it calls the true history behind the language, which is a good sign about the project's sense of humour and a distraction from the implementation.

The CI badge in the README header and the presence of a Valgrind test script, a clang-format configuration, a clang-tidy configuration, a cppcheck suppression file and a test_cases/ directory suggest the interpreter is treated as something to keep working, which is the difference between this and a keyword-renaming exercise.

## Two ways to reach raylib, one hand written and one generated

The most interesting feature is the FFI, and the README presents it as two different approaches to the same problem. The hand-written route is the optional rayrot native module, loaded with #cooked <raylib>, and it wraps about 20 raylib primitives while flattening everything into scalars. It loads rayrot/raylib.so, which is built by make rayrot, and deliberately not the system libraylib.so. The installation note is specific about a common mistake: on Ubuntu, apt-get install libraylib-dev does not exist, so you need the raylib PPA or a source build.

```bash
pkg-config --exists raylib     # confirm raylib is installed
make                           # build the interpreter
make rayrot                  # build the raylib binding (rayrot/raylib.so)
BRAINROT_PATH=rayrot ./brainrot examples/raylib/ohio_engine.brainrot
```

The generated route exists because raylib has 617 functions and hand-writing that many wrappers is not a plan. The tool rayrot/rayrot_gen.py reads raylib's own published API description.

```text
rayrot/raylib_api.json → rayrot-gen → { C adapters + ABI descriptors,
                                            a Brainrot prelude of gang types
                                            and gyatt constants, ABI tests }
```

That yields 378 functions and 16 struct types, and the calls take real aggregates by value instead of loose scalars.

```c
#cooked <raylibgen>

gang Vector2 pos;
gang Color orb;
rl_draw_circle_v(pos, 60.0, orb);   🚽 raylib's own DrawCircleV(Vector2, float, Color)
```

The three make targets split the work: make rayrot-gen-sources generates the binding and needs no raylib at all, make rayrot-gen adds compiling and the ABI drift check, and make rayrot-gen-sources plus make play-gen runs the example. Generating needs only Python and the pinned JSON, so a contributor can produce the binding without a C dependency on raylib.

## Layout mismatches become build failures, not corruption

The generated binding has one design decision that is worth more than the rest of the FFI work, and that is the static assertion. Every generated gang has its size, its alignment and every field offset asserted against the real raylib headers with _Static_assert, so a layout disagreement is a build failure rather than a runtime corruption. The README also says what is deliberately left out, struct returns most of all, and that the omission is counted and reported on every run rather than hidden.

The examples behind the two approaches are named: Ohio Engine, described as the first cursed game, is the hand-written route and it bounces an ABSOLUTE CINEMA orb around a window, while Ohio Engine II is the same loop through a generated binding. That pairing is the clearest way to see the difference between the two approaches. The hand-written module gives you a small, readable set of calls you can understand in a minute, and the generated one gives you the whole API with machine-checked layout, at the cost of a much larger surface you did not write.

The project documentation also covers what the generated path deliberately does not do, and the docs/rayrot.md file is the reference for the two-library model, the Ubuntu PPA versus source build difference, and the binding reference itself.

## Where an esoteric language is the wrong choice

Three situations point elsewhere. The first is any project where the code has to outlive the joke. A language whose keywords are slang is fine for a teaching artefact or a conference talk, and it is a liability in a repository that has to be read by people who were not there in 2026. The second is a performance or memory sensitive workload, where the interpreter is written in C but every value still goes through a tree walk and a dynamic library boundary for the standard library, so the C underneath buys you the interpreter rather than the program.

The third is a project that needs a library ecosystem. Brainrot has its own standard library, libstdrot.so, with a gamba() CSPRNG and a module system, and that is a real amount of work to keep equivalent to what an existing language gives you for free. If your goal is to experiment with parsing and code generation, the Flex and Bison source and the ASan and Valgrind setup are the interesting part and they are all in the repository. If your goal is to ship something, the same effort would be better spent writing the tool in a language with a package manager.

There is also a licensing angle worth naming. GPL-3.0 is the right licence for a language implementation and a meme, and it is the licence to check before you link against libstdrot.so in a product.

## Conclusion

Brainrot fits a programmer who wants a small language implementation to read, modify and break, especially one interested in lexer, parser and compiler design, and who will treat the keyword table as a joke rather than a specification. It does not fit a production project, and it does not fit a reader who expects the meme to be the point, because the actual engineering is in the module loading, the sanitizers and the generated binding. Before you build it, install Flex, Bison, a C compiler and the OpenSSL development headers, since the standard library's gamba() CSPRNG links libcrypto, and read the Installation Guide, because the per-platform dependency setup is where a first build usually goes wrong.

## FAQ

### What is the Brainrot programming language?

It is a C-like language where the keywords are replaced with internet slang, described in the README as a meme-inspired language that translates common programming keywords into meme references. The intent is to make it a fun way to learn about language processing and compiler design, and it is built with Flex and Bison.

### How do I build the Brainrot interpreter from source?

You need a C compiler, either GCC or Clang, plus Flex, Bison, and the OpenSSL development headers, because the standard library's gamba() CSPRNG links libcrypto. Then run make, which regenerates the lexer and parser and builds ./brainrot and libstdrot.so, and run a program with ./brainrot examples/hello_world.brainrot.

### What does the rayrot module do?

It lets a Brainrot program call raylib. The hand-written module wraps about 20 raylib primitives and flattens arguments into scalars, and it loads rayrot/raylib.so rather than the system libraylib.so. raylib is an optional dependency that is not needed for make or make test, and the README notes that on Ubuntu libraylib-dev does not exist as a package, so you need the raylib PPA or a source build.

### Why does the generated raylib binding exist?

Because raylib has 617 functions and hand-writing that many wrappers is not a plan. The generator rayrot/rayrot_gen.py reads raylib's own published API description and produces C adapters, ABI descriptors, a Brainrot prelude of gang types and gyatt constants, and ABI tests, yielding 378 functions and 16 struct types that take real aggregates by value.

### How does Brainrot check that the generated binding matches raylib?

Every generated gang has its size, its alignment and every field offset asserted against the real raylib headers with _Static_assert, so a layout disagreement is a build failure rather than a runtime corruption. What the generator deliberately leaves out, struct returns most of all, is counted and reported on every run.

## Sources

- [Brainrotlang/brainrot on GitHub](https://github.com/Brainrotlang/brainrot)
- [License: GPL-3.0](https://github.com/Brainrotlang/brainrot/blob/main/LICENSE)
- [Project website](https://brainrotlang.com/)
- [README](https://github.com/Brainrotlang/brainrot/blob/main/README.md)
- [Releases](https://github.com/Brainrotlang/brainrot/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/brainrotlang-brainrot
