Thank you for contributing to XVR Programming Language!
# Clone and build
git clone https://github.com/anomalyco/xvr.git
cd xvr
mkdir build && cd build
cmake .. && cmake --build .
# Run the compiler
./build/xvr your_program.xvr- Indentation: Use 4 spaces for all indentation
- Line Length: Keep lines under 100 characters when possible
- Formatter: Use
clang-formatfor automatic formatting - Pre-commit Hook: Automatically formats staged files on commit
The project includes a pre-commit hook that automatically formats C files:
# Install clang-format (if not already installed)
# Ubuntu/Debian:
sudo apt install clang-format
# macOS:
brew install clang-format
# The pre-commit hook runs automatically on git commit
# Unformatted files will be auto-formatted and re-stagedVS Code (.vscode/settings.json):
{
"editor.insertSpaces": true,
"editor.tabSize": 4,
"editor.trimAutoWhitespace": true,
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true
}Vim (.vimrc):
set tabstop=4
set shiftwidth=4
set expandtabxvr/
├── src/ # Core source files
│ ├── CMakeLists.txt # Library build config
│ ├── adapters/llvm/ # LLVM AOT backend
│ │ ├── xvr_llvm_codegen.cpp # Main code generator
│ │ ├── xvr_llvm_codegen.h # Codegen API
│ │ ├── xvr_llvm_expression_emitter.cpp # Expression codegen
│ │ ├── xvr_llvm_function_emitter.cpp # Function codegen
│ │ ├── xvr_llvm_optimizer.cpp # LLVM optimization pipeline
│ │ └── *.cpp/*.h # LLVM infrastructure
│ ├── sema/ # Semantic analysis
│ │ ├── xvr_builtin.cpp # Module resolver, builtins
│ │ └── xvr_builtin.h # Builtin API
│ ├── optimizer/ # AST optimization passes
│ │ ├── xvr_ast_optimizer.h # PassManager interface
│ │ └── xvr_ast_optimizer.cpp # Pass implementations
│ ├── core/ # Core types and utilities
│ │ └── ast/ # AST node definitions
│ ├── xvr_*.cpp # Parser, lexer, AST, etc.
│ └── xvr_common.h # Version info, common definitions
├── compiler/ # Compiler executable source
│ └── main_compiler.c # Compiler entry point
├── test/ # Unit tests
│ ├── CMakeLists.txt # Test build config
│ └── test_*.cpp # Individual test modules
├── stage0/ # Bootstrap compiler (written in XVR)
│ ├── src/ # Stage0 source files
│ └── stage0 # Bootstrap binary
├── fuzzer/ # Fuzz testing scripts
│ ├── run_tests.sh # Edge case tests
│ └── corpus/ # Valid test inputs
├── docs/ # Documentation
├── CMakeLists.txt # Root build config
└── build/ # Build output (generated)
# Create build directory
mkdir build && cd build
# Configure (Debug build by default)
cmake ..
# Build everything (compiler, library, tests)
cmake --build .
# Clean build artifacts
rm -rf build| Option | Values | Default | Description |
|---|---|---|---|
CMAKE_BUILD_TYPE |
Debug, Release | Debug | Build type |
XVR_BUILD_TESTS |
ON, OFF | ON | Build test suite |
XVR_BUILD_SHARED |
ON, OFF | ON | Build shared library |
XVR_BUILD_STATIC |
ON, OFF | ON | Build static library |
XVR_SANITIZE |
address, undefined, thread, all | - | Enable sanitizers |
# Release build with optimizations
cmake -DCMAKE_BUILD_TYPE=Release ..
# Enable debug mode with assertions
cmake -DCMAKE_BUILD_TYPE=Debug ..
# Enable AddressSanitizer (detect memory errors)
cmake -DXVR_SANITIZE=address ..
# Enable UBSan (undefined behavior)
cmake -DXVR_SANITIZE=undefined ..
# Enable both ASan and UBSan
cmake -DXVR_SANITIZE=all ..
# Build without tests
cmake -DXVR_BUILD_TESTS=OFF ..# Run unit tests (from build directory)
ctest --output-on-failure
# Run all tests verbosely
ctest -V
# Run specific test
./build/xvr_test_all
# Run fuzzer test suite (finds edge case bugs)
bash fuzzer/fuzz_test_suite.sh
# Run stress tests (500+ random inputs)
bash fuzzer/stress_test.shtest/test_all.c- Main test runnertest/test_*.c- Individual test modules (lexer, parser, stdlib, etc.)fuzzer/fuzz_test_suite.sh- Edge case fuzzerfuzzer/stress_test.sh- Random stress testingfuzzer/corpus/- Valid test inputs for fuzzing
- Add your test function to the appropriate
test_*.cfile - Register it in
test_all.c - Rebuild and run tests
The fuzzer tests edge cases and potential bug triggers:
- Array out-of-bounds access
- Division by zero
- Type mismatches
- Infinite recursion
- Undefined variables
- And more...
Run the full fuzzer suite:
bash fuzzer/fuzz_test_suite.shThe code/ directory contains example XVR programs demonstrating features:
# Run an example
./build/xvr code/conditional.xvr
./build/xvr code/loop_while.xvrUse the color-coded error macros:
#include "xvr_console_colors.h"
fprintf(stderr, XVR_CC_ERROR "Error: %s\n" XVR_CC_RESET, message);
fprintf(stderr, XVR_CC_NOTICE "Notice: %s\n" XVR_CC_RESET, message);- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Make your changes following the code style
- Test your changes:
rm -rf build && mkdir build && cd build cmake .. && cmake --build . # Build ./xvr_test_all # Run tests (should be 94/94) # OR ctest --output-on-failure # Run tests via CTest bash ../stage0/build.sh # Verify stage0 bootstrap
- Commit - The pre-commit hook will auto-format your staged files
- Push to your fork
- Submit a pull request
Note: The pre-commit hook automatically formats C files with
clang-format. If your files are reformatted, simply commit again after the hook re-stages them.
Use clear, descriptive commit messages:
fix: resolve segfault in codegenadd: type mismatch error detectionupdate: Windows installation docsdocs: update documentations
- Add enum value to
xvr_ast_node.h(Xvr_ASTNodeType) - Add struct definition in
xvr_ast_node.h - Add case to
Xvr_createASTNode()inxvr_ast_node.c - Add case to
Xvr_freeASTNode()inxvr_ast_node.c - Add parser handling in
xvr_parser.c - Add codegen in LLVM backend if needed
- Add opcode to
xvr_opcodes.h - Add parser handling
- Add LLVM codegen in
src/backend/
To add a new AST optimization pass:
- Add pass type to
xvr_ast_optimizer.h:
typedef enum {
// ... existing passes ...
XVR_PASS_YOUR_NEW_PASS
} Xvr_ASTPassType;- Implement the pass function:
static Xvr_ASTOptimizerResult run_your_pass(Xvr_ASTNode** node, void* context) {
Xvr_ASTOptimizerResult result = {XVR_OPT_RESULT_SUCCESS, 0, NULL};
// Implement your optimization logic
return result;
}- Register the pass in
Xvr_ASTOptimizerAddStandardPasses():
Xvr_ASTOptimizerPass new_pass = {
.type = XVR_PASS_YOUR_NEW_PASS,
.name = "your_pass_name",
.run = run_your_pass,
.context = your_context,
.priority = 5, // Higher = runs later
.enabled = true
};
Xvr_ASTOptimizerAddPass(opt, &new_pass);When adding print functionality, note the language design:
- String literals can be printed directly:
std::print("hello") - Non-string types require format specifiers:
std::print("{}", 42) - Variables of any type require format specifiers:
std::print("{}", myVar) - Arrays can be printed directly (elements printed with spaces)
// Valid
std::print("hello\n"); // Direct string
std::print("value: {}\n", 42); // With format specifier
var x = 10;
std::print("{}", x); // Variable requires {}
var arr = [1, 2, 3];
std::print(arr); // Arrays OK directly
// Invalid - will cause compile error
std::print(42); // Non-string literal without format
var name = "arfy";
std::print(name); // Variable needs format: std::print("{}", name)
Include:
- Description of the bug
- Steps to reproduce
- Expected vs actual behavior
- Environment (OS, LLVM version)
- Input file if applicable
- Fuzzer tests pass (
bash fuzzer/fuzz_test_suite.sh) - Stress tests pass (
bash fuzzer/stress_test.sh) - No memory leaks (run with
SANITIZE=address) - No compiler warnings
- Documentation updated if needed
Look for // BUG, // TODO, or // FIXME comments in the code for starting points.
Note
This project uses LLVM for AOT compilation. The interpreter runtime has been removed - all code compiles to native executables via LLVM.