Thank you for your interest in contributing to the O²L programming language! This document provides guidelines for contributing to the project.
- C++23 compatible compiler (GCC 12+, Clang 15+, or MSVC 2022+)
- CMake 3.20+
- Google Test (for running tests)
- Git
-
Fork and clone the repository:
git clone https://github.com/your-username/o2l.git cd o2l -
Create a development build:
mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Debug make
-
Run tests to ensure everything works:
cd tests ./o2l_tests -
Test the interpreter:
cd .. ./o2l run ../examples/minimal_test.obq
- Bug fixes: Fix issues in the interpreter, parser, or runtime
- Feature development: Add new language features or system libraries
- Documentation: Improve README, add examples, write tutorials
- Testing: Add test cases, improve test coverage
- Performance: Optimize parsing, runtime, or memory usage
- Tooling: Improve build system, CI/CD, or development tools
-
Create a feature branch:
git checkout -b feature/your-feature-name
-
Make your changes following the coding standards below
-
Write or update tests for your changes
-
Run the full test suite:
cd build/tests ./o2l_tests -
Test with example programs:
cd build ./o2l run ../examples/test_final_demo.obq -
Format your code:
clang-format -i src/**/*.cpp src/**/*.hpp
-
Commit your changes:
git add . git commit -m "feat: add support for new feature"
-
Push and create a pull request:
git push origin feature/your-feature-name
- Follow the
.clang-formatconfiguration provided in the repository - Use modern C++23 features where appropriate
- Prefer smart pointers (
std::unique_ptr,std::shared_ptr) over raw pointers - Use meaningful variable and function names
- Add comments for complex logic, but let code be self-documenting
- Follow RAII principles
// Good
auto parseExpression() -> std::unique_ptr<ASTNode> {
auto node = std::make_unique<ExpressionNode>();
// ... implementation
return node;
}
// Avoid
ASTNode* parseExpression() {
ASTNode* node = new ExpressionNode();
// ... implementation
return node; // Memory leak potential
}- Use clear, descriptive names for objects and methods
- Follow the existing patterns in example files
- Use proper capitalization:
Object,Enum,Record,Protocol - Mark public methods with
@external - Include system imports at the top of files
import system.io
Object Calculator {
property value: Int
constructor(initialValue: Int) {
this.value = initialValue
}
@external method add(amount: Int): Int {
return this.value + amount
}
method internalValidation(): Bool {
return this.value >= 0
}
}
- Every new feature should include comprehensive tests
- Bug fixes should include regression tests
- Use descriptive test names that explain what is being tested
-
Unit Tests (
test_*.cpp):- Test individual components (lexer, parser, runtime)
- Fast execution, no I/O dependencies
- Use Google Test framework
-
Integration Tests (
test_integration.cpp):- Test complete program execution
- Use actual
.obqexample files - Verify expected behavior and error handling
-
Example Programs (
examples/*.obq):- Real-world usage examples
- Should compile and run successfully
- Used in integration testing
// Unit test example
TEST_F(ParserTest, ParseObjectDeclaration) {
auto nodes = parse(R"(
Object TestObject {
@external method test(): Int {
return 42
}
}
)");
ASSERT_EQ(nodes.size(), 1);
auto object_node = dynamic_cast<ObjectNode*>(nodes[0].get());
ASSERT_NE(object_node, nullptr);
EXPECT_EQ(object_node->getName(), "TestObject");
}When reporting bugs, please include:
- O²L version (
./o2l --version) - Operating system and compiler version
- Minimal reproducible example
- Expected vs actual behavior
- Error messages and stack traces
**Bug Description:**
Parser fails when parsing nested record access
**Environment:**
- O²L version: 0.0.1
- OS: Ubuntu 22.04
- Compiler: GCC 12.2
**Minimal Example:**
```o2l
Record Point { x: Int, y: Int }
Record Line { start: Point, end: Point }
Object Main {
method main(): Int {
line: Line = Line(start=Point(x=0, y=0), end=Point(x=10, y=10))
return line.start.x # This fails
}
}Expected: Should return 0 Actual: Syntax error: "Unexpected token '.'"
### Feature Requests
- **Describe the use case** and motivation
- **Provide examples** of how the feature would be used
- **Consider alternatives** and explain why they're insufficient
- **Check existing issues** to avoid duplicates
## 🏗️ Architecture Overview
### Project Structure
/src/ ├── main.cpp # CLI entry point ├── Lexer.{cpp,hpp} # Tokenization ├── Parser.{cpp,hpp} # AST generation ├── Interpreter.{cpp,hpp} # Program execution ├── AST/ # AST node implementations │ ├── Node.hpp # Base AST node │ ├── ObjectNode.{cpp,hpp} │ ├── MethodCallNode.{cpp,hpp} │ └── ... └── Runtime/ # Runtime system ├── Value.{cpp,hpp} # Value types ├── Context.{cpp,hpp} # Execution context ├── ObjectInstance.{cpp,hpp} └── ...
/tests/ ├── test_lexer.cpp # Lexer unit tests ├── test_parser.cpp # Parser unit tests ├── test_runtime.cpp # Runtime unit tests └── test_integration.cpp # Integration tests
/examples/ ├── minimal_test.obq # Basic functionality ├── test_final_demo.obq # Advanced features └── ...
### Key Components
- **Lexer**: Converts source code into tokens
- **Parser**: Builds Abstract Syntax Tree (AST) from tokens
- **AST Nodes**: Represent language constructs (objects, methods, etc.)
- **Runtime**: Executes AST with context management
- **Value System**: Handles O²L's object-oriented values
## 🎨 Adding New Features
### Language Features
When adding new language features:
1. **Update the lexer** to recognize new keywords/syntax
2. **Add parser support** for the new construct
3. **Create AST nodes** to represent the feature
4. **Implement runtime behavior** in the interpreter
5. **Add comprehensive tests**
6. **Update documentation** and examples
### Example: Adding a new keyword
```cpp
// 1. Lexer.cpp - Add token type
enum class TokenType {
// ... existing tokens
ASYNC, // New token
};
// 2. Parser.cpp - Handle new syntax
if (token.type == TokenType::ASYNC) {
return parseAsyncMethod();
}
// 3. Create AsyncMethodNode.{cpp,hpp}
class AsyncMethodNode : public ASTNode {
// ... implementation
};
// 4. Add runtime support in Interpreter.cpp
// 5. Add tests in test_parser.cpp and test_integration.cpp
We follow Semantic Versioning:
- MAJOR.MINOR.PATCH (e.g., 0.0.1)
- Major: Breaking changes to language syntax or semantics
- Minor: New features, backward compatible
- Patch: Bug fixes, no new features
- All tests pass
- Documentation updated
- CHANGELOG.md updated
- Version numbers updated
- Create release tag
- GitHub Actions builds successfully
- Release artifacts generated
- GitHub Discussions: For general questions and ideas
- GitHub Issues: For bug reports and feature requests
- Code Review: All pull requests are reviewed by maintainers
- Community: Join our community discussions
Contributors are recognized in:
- CONTRIBUTORS.md file
- Release notes for major contributions
- Git commit history
By contributing to O²L, you agree that your contributions will be licensed under the Apache License 2.0.
Thank you for contributing to O²L! 🎉