Skip to content

Latest commit

 

History

History
346 lines (267 loc) · 9.38 KB

File metadata and controls

346 lines (267 loc) · 9.38 KB

Contributing to XVR

Thank you for contributing to XVR Programming Language!

Quick Start

# 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

Code Style

  • Indentation: Use 4 spaces for all indentation
  • Line Length: Keep lines under 100 characters when possible
  • Formatter: Use clang-format for automatic formatting
  • Pre-commit Hook: Automatically formats staged files on commit

Automatic Formatting

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-staged

Editor Examples

VS 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 expandtab

Project Structure

xvr/
├── 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)

Building

# 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

Build Options

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

Build Examples

# 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 ..

Testing

Running Tests

# 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.sh

Test Structure

  • test/test_all.c - Main test runner
  • test/test_*.c - Individual test modules (lexer, parser, stdlib, etc.)
  • fuzzer/fuzz_test_suite.sh - Edge case fuzzer
  • fuzzer/stress_test.sh - Random stress testing
  • fuzzer/corpus/ - Valid test inputs for fuzzing

Adding Tests

  1. Add your test function to the appropriate test_*.c file
  2. Register it in test_all.c
  3. Rebuild and run tests

Fuzz Testing

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.sh

Code Examples

The code/ directory contains example XVR programs demonstrating features:

# Run an example
./build/xvr code/conditional.xvr
./build/xvr code/loop_while.xvr

Error Handling

Use 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);

Making Changes

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Make your changes following the code style
  4. 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
  5. Commit - The pre-commit hook will auto-format your staged files
  6. Push to your fork
  7. 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.

Commit Messages

Use clear, descriptive commit messages:

  • fix: resolve segfault in codegen
  • add: type mismatch error detection
  • update: Windows installation docs
  • docs: update documentations

Adding New Features

New AST Nodes

  1. Add enum value to xvr_ast_node.h (Xvr_ASTNodeType)
  2. Add struct definition in xvr_ast_node.h
  3. Add case to Xvr_createASTNode() in xvr_ast_node.c
  4. Add case to Xvr_freeASTNode() in xvr_ast_node.c
  5. Add parser handling in xvr_parser.c
  6. Add codegen in LLVM backend if needed

New Backend Operations

  1. Add opcode to xvr_opcodes.h
  2. Add parser handling
  3. Add LLVM codegen in src/backend/

New Optimization Passes

To add a new AST optimization pass:

  1. Add pass type to xvr_ast_optimizer.h:
typedef enum {
    // ... existing passes ...
    XVR_PASS_YOUR_NEW_PASS
} Xvr_ASTPassType;
  1. 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;
}
  1. 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);

Print/Println Behavior

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)

Reporting Bugs

Include:

  • Description of the bug
  • Steps to reproduce
  • Expected vs actual behavior
  • Environment (OS, LLVM version)
  • Input file if applicable

Code Review Criteria

  • 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

Topics for Contribution

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.