# Cobble API Documentation
This document describes the internal API for Cobble's compiler and tools.
## Overview
Cobble consists of several modules that work together to compile high-level code into Minecraft data packs:
- **Parser** - Converts source code into an Abstract Syntax Tree (AST)
- **Transpiler** - Transforms AST into Minecraft commands
- **Standard Library** - Provides event handling and utilities
- **CLI** - Command-line interface for building projects
## Module: Parser
The parser module is organized into several files:
### `parser/mod.rs`
Public API for the parser module. Exports the main `parse` function and re-exports components from submodules.
### `parser/tokenizer.rs`
Manual tokenizer that handles indentation with INDENT/DEDENT tokens and distinguishes `/` division from `/` command prefix.
**Key Features:**
- Tracks indentation levels to generate INDENT/DEDENT tokens
- Handles string literals with proper escaping
- Distinguishes between division operator (`a / b`) and command prefix (`/say`)
- Processes inline comments (starting with `#`)
### `parser/combinators.rs`
The main parser built with chumsky combinator library that handles Python-style indented syntax.
#### Function: `parse(source: &str) -> Result<Program, Vec<String>>`
Parses Cobble source code into an AST using chumsky parser combinators.
**Parameters:**
- `source` - The source code string to parse
**Returns:**
- `Ok(Program)` - Successfully parsed program
- `Err(Vec<String>)` - Parse errors with messages
**Example:**
```rust
use cobble::parser::parse;
let source = r#"
def hello():
/say Hello, world!
"#;
let program = parse(source)
.map_err(|errors| errors.join(", "))?;
```
**Implementation Details:**
- Uses chumsky 0.11 parser combinator library
- Supports all Cobble syntax including execute blocks, global keyword, and complex expressions
- **Operator precedence**: Four-level precedence for expressions (pow > mul/div/mod > add/sub > comparisons)
- **Multi-operator expressions**: Chains operations using `.foldl().repeated()` pattern
- Error reporting integrated with ariadne for beautiful error messages
**Historical Parser Enhancements**:
- Fixed division operator tokenization to correctly distinguish `a / b` from `/command`
- Implemented proper operator precedence (multiplication and division before addition and subtraction)
- Added support for chained multi-operator expressions like `a + b + c` and `x * y * z`
## Module: AST
### `ast.rs`
Defines the Abstract Syntax Tree structures.
#### Struct: `Program`
Represents a complete Cobble program.
```rust
pub struct Program {
pub imports: Vec<Import>,
pub statements: Vec<Statement>,
}
```
#### Enum: `Statement`
Represents different types of statements.
```rust
pub enum Statement {
Import(Import),
FunctionDef(FunctionDef),
Assignment(Assignment),
ConstAssignment(ConstAssignment), // v0.3.0
Expression(Expression),
If(IfStatement),
For(ForLoop),
While(WhileLoop),
Match(MatchStatement), // v0.3.0
Return(Option<Expression>),
Pass,
MinecraftCommand(String),
Global(Vec<String>),
Execute(ExecuteBlock),
SelectorDef(SelectorDef), // v0.4.0
EntityDef(EntityDef),
CreateEntity(String),
}
```
**Recent Additions:**
- **v0.4.0**: `SelectorDef` - Entity selector definitions (e.g., `@Player = @a[type=player]`)
- **v0.3.0**: `ConstAssignment` - Compile-time constants (e.g., `const MAX_HEALTH = 100`)
- **v0.3.0**: `Match` - Match/switch statements with literal, range, and wildcard patterns
#### Struct: `FunctionDef`
Represents a function definition.
```rust
pub struct FunctionDef {
pub name: String,
pub params: Vec<Parameter>,
pub body: Vec<Statement>,
pub decorators: Vec<String>,
}
```
#### Struct: `Parameter`
Represents a function parameter.
```rust
pub struct Parameter {
pub name: String,
pub default: Option<Expression>,
}
```
#### Struct: `ConstAssignment` (v0.3.0)
Represents a compile-time constant assignment.
```rust
pub struct ConstAssignment {
pub target: String,
pub value: Expression,
}
```
Constants are evaluated at compile time and replaced with their literal values.
#### Struct: `MatchStatement` (v0.3.0)
Represents a match/switch statement.
```rust
pub struct MatchStatement {
pub value: Expression, // Expression to match against
pub cases: Vec<MatchCase>,
}
pub struct MatchCase {
pub pattern: MatchPattern,
pub body: Vec<Statement>,
}
pub enum MatchPattern {
Literal(i32), // case 5:
Range(i32, i32), // case 1 to 10:
Wildcard, // case _:
}
```
Match statements compile to efficient 4-way split algorithm for optimal branching.
#### Struct: `SelectorDef` (v0.4.0)
Represents an entity selector definition.
```rust
pub struct SelectorDef {
pub name: String, // e.g., "Player"
pub selector: String, // e.g., "@a[type=player,gamemode=survival]"
}
```
Selector aliases are replaced at compile time with zero runtime overhead.
#### Enum: `Expression`
Represents different types of expressions.
```rust
pub enum Expression {
Number(f64),
String(String),
Boolean(bool),
None,
Array(Vec<Expression>),
Map(Vec<(String, Expression)>),
Identifier(String),
Attribute(Box<Expression>, String),
Binary(Box<Expression>, BinaryOp, Box<Expression>),
Unary(UnaryOp, Box<Expression>),
Call(Box<Expression>, Vec<Expression>),
Subscript(Box<Expression>, Box<Expression>),
}
```
#### Enum: `BinaryOp`
Binary operators.
```rust
pub enum BinaryOp {
Add, Sub, Mul, Div, Mod, Pow,
Eq, NotEq, Lt, LtEq, Gt, GtEq,
And, Or,
}
```
## Module: Transpiler
The transpiler module is organized into several files:
### `transpiler/mod.rs`
Main transpiler that converts AST into Minecraft data pack format.
#### Struct: `Transpiler`
The main transpiler instance.
```rust
pub struct Transpiler {
data_pack: DataPack,
current_function: Option<Vec<String>>,
current_context: FunctionContext,
variables: HashMap<String, Expression>,
module_level_vars: HashMap<String, Expression>, // Top-level variables to initialize
constants: HashMap<String, i32>, // v0.3.0: Compile-time constants
selector_aliases: HashMap<String, String>, // v0.4.0: Entity selector definitions
imported_files: HashSet<PathBuf>, // v0.4.0: Imported file tracking
current_file_dir: PathBuf, // v0.4.0: Current file directory for imports
temp_counter: u32,
variable_objectives: HashMap<String, String>, // Tracks which objective each variable uses
function_params: HashMap<String, Vec<String>>, // Tracks parameter names for each function
}
```
### `transpiler/command_processor.rs`
Processes Minecraft command strings with variable substitution.
**Key Features:**
- Substitutes function parameters (macro variables)
- Converts scoreboard variables in JSON text components
- Handles selector alias replacement
- Escapes strings properly for Minecraft commands
### `transpiler/expression_evaluator.rs`
Evaluates complex expressions into scoreboard operations.
**Key Features:**
- Converts arithmetic expressions to scoreboard operations
- Handles power operator with compile-time expansion
- Generates temporary variables for intermediate results
- Optimizes self-assignment operations
### `transpiler/condition_translator.rs`
Translates Python-style conditions to Minecraft execute conditions.
**Key Features:**
- Converts comparison operators to scoreboard matches
- Handles boolean AND/OR/NOT operators
- Supports literal comparisons on both sides
- Generates OR logic using temporary variables
### `transpiler/data_pack.rs`
Manages data pack structure and file generation.
**Key Features:**
- Tracks objectives and functions
- Generates `pack.mcmeta` with the supported pack format
- Creates modern `data/<namespace>/function` and `data/<namespace>/tags/function` files
- Writes namespaced JSON resources such as predicates, recipes, dialogs, and tags
- Handles standard library event listeners
### `transpiler/statement_processors/`
Individual processors for each statement type:
- `assignment.rs` - Variable assignments with type checking
- `if_processor.rs` - If/elif/else statements with function extraction
- `loop_processor.rs` - For and while loops
- `match_processor.rs` - Match/switch statements with 4-way split
- `execute_processor.rs` - Execute block modifiers
- `selector_processor.rs` - Selector definitions
**Historical Transpiler Enhancements:**
- **v0.4.0**:
- **Entity selector definitions**: Custom selector aliases with compile-time replacement
- **File import system**: Import functions and definitions from other `.cbl` files
- **Circular dependency prevention**: Automatic detection via `imported_files` HashSet
- **Relative import resolution**: Resolve imports relative to current file location
- **v0.3.0**:
- **Compile-time constants**: `const` keyword for constant declarations
- **Match/switch statements**: Efficient multi-way branching with 4-way split algorithm
- **v0.1.0**:
- **Module-level variable initialization**: Top-level assignments are automatically initialized in `_cobble_init`
- **Complex expression evaluation**: New `evaluate_expression_to_target()` helper handles nested binary expressions
- **Correct loop variable objectives**: Loop variables (like `i` in for loops) now correctly track their objective
- **Duplicate objective prevention**: `ensure_init_function()` checks for existing objectives before adding
#### Implementation: `Transpiler`
##### `new(namespace: String, output_dir: PathBuf) -> Self`
Creates a new transpiler instance.
**Parameters:**
- `namespace` - The data pack namespace
- `output_dir` - Output directory path
##### `transpile(&mut self, program: &Program) -> Result<(), String>`
Transpiles a program into a data pack.
**Parameters:**
- `program` - The parsed program AST
**Returns:**
- `Ok(())` - Successfully transpiled
- `Err(String)` - Transpilation error
##### `write_data_pack(&self) -> std::io::Result<()>`
Writes the data pack to disk.
**Example:**
```rust
use cobble::pack_format::PackFormat;
use cobble::transpiler::Transpiler;
use cobble::parser::parse;
use std::path::PathBuf;
let source = "...";
let program = parse(source)
.map_err(|errors| errors.join(", "))?;
let mut transpiler = Transpiler::new(
"my_namespace".to_string(),
PathBuf::from("./output")
);
transpiler.transpile(&program)?;
transpiler.write_data_pack()?;
```
### Struct: `DataPack`
Represents a Minecraft data pack.
```rust
pub struct DataPack {
pub namespace: String,
pub description: String,
pub output_dir: PathBuf,
pub functions: HashMap<String, Vec<String>>,
pub tags: HashMap<String, Vec<String>>,
pub advancements: HashMap<String, String>,
pub loot_tables: HashMap<String, String>,
pub recipes: HashMap<String, String>,
pub predicates: HashMap<String, String>,
pub item_modifiers: HashMap<String, String>,
pub json_resources: HashMap<String, String>,
pub command_metadata: HashMap<String, HashMap<usize, GeneratedCommand>>,
pub pack_format: PackFormat, // Cobble v0.6.3 requires 101.1
pub stdlib: StdLib,
pub used_objectives: HashSet<String>,
pub source_display_root: Option<PathBuf>,
}
```
**Note**: `pack_format` uses the `PackFormat` enum. Cobble v0.6.3 targets Minecraft Java Edition 26.1.2 and requires `PackFormat::Decimal(101, 1)`, serialized into `pack.mcmeta` as `min_format` and `max_format` arrays.
#### Methods
##### `new(namespace: String, output_dir: PathBuf) -> Self`
Creates a new data pack.
##### `add_function(&mut self, name: String, commands: Vec<String>)`
Adds a function to the data pack.
##### `write(&self) -> std::io::Result<()>`
Writes the data pack to the file system, including `.cobble/source_map.json`
when generated command metadata exists and `.cobble/build_manifest.json` for
build metadata. Source-map source paths are normalized against
`source_display_root` when available.
##### `set_source_display_root(&mut self, root: PathBuf)`
Sets the display root used to avoid unnecessary absolute source paths in
`.cobble/source_map.json`.
### Struct: `BuildManifest`
Summary metadata written to `.cobble/build_manifest.json`.
```rust
pub struct BuildManifest {
pub version: u8,
pub cobble_version: String,
pub minecraft_version: String,
pub pack_format: PackFormat,
pub pack_format_text: String,
pub namespace: String,
pub description: String,
pub input: Option<BuildManifestInput>,
pub generated_namespaces: Vec<String>,
pub generated: BuildManifestGenerated,
pub resources: Vec<BuildManifestResourceEntry>,
pub validation: Option<BuildManifestValidation>,
}
pub struct BuildManifestInput {
pub source: String,
pub entry_points: Vec<String>,
pub compiled_files: Vec<String>,
}
pub struct BuildManifestResourceEntry {
pub kind: String,
pub namespace: String,
pub path: String,
}
pub struct BuildManifestValidation {
pub enabled: bool,
pub commands_json: String,
pub files_checked: usize,
pub commands_checked: usize,
pub macro_commands_checked: usize,
pub commands_skipped: usize,
pub errors: usize,
pub source_map_errors: usize,
}
```
## Module: Standard Library
### `stdlib.rs`
Provides the Cobble standard library implementation.
#### Struct: `StdLib`
```rust
pub struct StdLib {
event_listeners: HashMap<EventType, Vec<String>>,
}
```
#### Enum: `EventType`
```rust
pub enum EventType {
Load,
Tick,
Custom(String),
}
```
#### Methods
##### `new() -> Self`
Creates a new standard library instance.
##### `add_event_listener(&mut self, event_type: EventType, function_name: String)`
Registers a function as an event listener.
**Parameters:**
- `event_type` - The type of event to listen for
- `function_name` - The name of the function to call
##### `generate_tags(&self, namespace: &str) -> HashMap<String, Vec<String>>`
Generates Minecraft function tags for registered events.
**Returns:**
- HashMap of tag names to function lists
## Module: Configuration
### `config.rs`
Handles project configuration.
#### Struct: `CobbleConfig`
```rust
pub struct CobbleConfig {
pub project: ProjectConfig,
pub build: BuildConfig,
}
pub struct ProjectConfig {
pub name: String,
pub description: String,
pub namespace: String,
pub version: String,
pub pack_format: String,
}
pub struct BuildConfig {
pub source: String,
pub output: String,
pub entry_points: Vec<String>,
}
```
#### Functions
##### `CobbleConfig::load(path: impl AsRef<Path>) -> Result<CobbleConfig, String>`
Loads and validates configuration from a `cobble.toml` file.
##### `CobbleConfig::load_unvalidated(path: impl AsRef<Path>) -> Result<CobbleConfig, String>`
Loads configuration without enforcing the current release's pack format. The build command uses this only when the user explicitly overrides `--pack-format`.
##### `CobbleConfig::default_with_name(name: String) -> CobbleConfig`
Creates a default configuration.
## Module: Commands
### `commands/build.rs`
Handles the `build` command.
#### Function: `build(options: BuildOptions) -> Result<(), String>`
Executes the build command.
**Parameters:**
- `options` - Input/output paths, namespace, pack format, zip, and validation settings
**Returns:**
- `Ok(())` - Build succeeded
- `Err(String)` - Build error
### `commands/init.rs`
Handles the `init` command.
#### Function: `init(options: InitOptions) -> Result<(), String>`
Initializes a new Cobble project.
### `commands/validate.rs`
Handles command-tree validation for generated data packs.
#### Function: `validate(options: ValidateOptions) -> Result<(), String>`
Validates `.mcfunction` files against `data/commands.json` and checks generated source maps when present.
### `commands/doctor.rs`
Handles project and environment diagnostics.
#### Function: `doctor(options: DoctorOptions) -> Result<(), String>`
Reports Cobble version, Minecraft target, pack format, Java/curl availability,
project config status, and command-tree fingerprint status without contacting
the network.
### `commands/inspect.rs`
Handles generated metadata inspection.
#### Function: `inspect(options: InspectOptions) -> Result<(), String>`
Reads `.cobble/build_manifest.json` and `.cobble/source_map.json` from a
generated data pack directory and prints either a text summary or formatted JSON.
### `commands/check.rs`
Handles the `check` command.
#### Function: `check(input: Option<PathBuf>) -> Result<(), String>`
Checks source files for syntax errors.
### `commands/watch.rs`
Handles the `watch` command.
#### Function: `watch(...) -> Result<(), String>`
Watches files for changes and rebuilds automatically.
## Error Handling
### Module: `error.rs`
#### Enum: `CobbleError`
```rust
pub enum CobbleError {
ParseError(String),
IoError(std::io::Error),
TranspileError(String),
}
```
All compiler errors are wrapped in this enum for consistent handling.
## Usage Examples
### Basic Compilation
```rust
use cobble::parser::parse;
use cobble::transpiler::Transpiler;
use std::path::PathBuf;
fn compile(source: &str, output_dir: &str) -> Result<(), String> {
// Parse
let program = parse(source)
.map_err(|errors| format!("Parse errors: {}", errors.join(", ")))?;
// Transpile
let mut transpiler = Transpiler::new(
"my_pack".to_string(),
PathBuf::from(output_dir)
);
transpiler.transpile(&program)
.map_err(|e| format!("Transpile error: {}", e))?;
// Write
transpiler.write_data_pack()
.map_err(|e| format!("IO error: {}", e))?;
Ok(())
}
```
### Custom Data Pack Options
```rust
use cobble::transpiler::Transpiler;
let mut transpiler = Transpiler::new(
"custom_pack".to_string(),
PathBuf::from("./output")
);
// Customize pack settings
transpiler.set_description("My Custom Data Pack".to_string());
transpiler.set_pack_format(PackFormat::Decimal(101, 1)); // Minecraft Java Edition 26.1.2
transpiler.transpile(&program)?;
transpiler.write_data_pack()?;
```
### AST Traversal
```rust
use cobble::ast::{Statement, Expression};
fn count_functions(program: &Program) -> usize {
program.statements.iter().filter(|stmt| {
matches!(stmt, Statement::FunctionDef(_))
}).count()
}
fn find_minecraft_commands(statements: &[Statement]) -> Vec<String> {
statements.iter().filter_map(|stmt| {
match stmt {
Statement::MinecraftCommand(cmd) => Some(cmd.clone()),
_ => None
}
}).collect()
}
```
## Internal Architecture
### Compilation Pipeline
```
Source Code (.cbl)
↓
[Parser] - Lexical Analysis & Parsing
↓
Abstract Syntax Tree (AST)
↓
[Transpiler] - Code Generation
↓
Minecraft Commands
↓
[DataPack Writer] - File Generation
↓
Data Pack (.mcfunction files, pack.mcmeta, tags)
```
### Key Design Decisions
1. **Python-style Syntax**: Familiar to many programmers, clean and readable
2. **chumsky Parser Combinators**: Modern, composable parsing with excellent error handling
3. **Operator Precedence**: Four-level precedence system matches standard mathematical conventions (pow > mul/div/mod > add/sub > comparisons)
4. **Complex Expression Handling**: Recursive evaluation for nested binary expressions with temporary variables
5. **Macro-based Parameters**: Uses Minecraft's function macro system for function parameters
6. **Automatic Recursion**: For loops and while loops compile to recursive functions
7. **Separate Functions for Complex Control Flow**: Nested if statements become separate functions to avoid command limit issues
8. **Scoreboard Variables**: All variables are stored as scoreboard objectives with proper tracking
9. **Module-level Initialization**: Top-level variables automatically initialized at pack load
10. **ariadne Error Reporting**: Beautiful, user-friendly error messages with context
## Performance Considerations
### Compilation Speed
- Parsing is O(n) where n is source code length
- Transpilation is O(m) where m is AST node count
- File writing is O(f) where f is function count
### Generated Code Size
- Simple functions: 1-10 commands
- For loops: 2-3 functions (init + loop function)
- While loops: 1-2 functions
- Nested control flow: Additional helper functions as needed
## Contributing
When adding new features to the API:
1. Update the AST structures in `ast.rs`
2. Add parser support in `parser.rs` using chumsky combinators
3. Implement transpilation in `transpiler.rs`
4. Add tests in `tests/`
5. Update this documentation
### Parser Development
When extending the parser:
- Tokenizer is in `parser.rs::tokenize()` - handles lexical analysis and indentation
- Parser combinators are in `parser.rs::token_parser()` - handles syntax analysis
- Use chumsky's `recursive()` for nested structures
- Test with both unit tests in `parser.rs` and integration tests in `tests/`
## Further Reading
- [Language Reference](language.md) - Cobble language syntax
- [CLI Documentation](cli.md) - Command-line usage
- [Examples](../examples/) - Example code
- [Rust Documentation](https://doc.rust-lang.org/book/) - Rust programming language