| Crates.io | MotoGarage_parser |
| lib.rs | MotoGarage_parser |
| version | 0.1.5 |
| created_at | 2025-11-08 21:02:00.686723+00 |
| updated_at | 2025-11-11 19:15:07.763297+00 |
| description | A parser and interpreter for MotoGarage DSL, a language for managing motorcycle collections. |
| homepage | |
| repository | https://github.com/YaroslavShakh/MotoGarage_Parser |
| max_upload_size | |
| id | 1923270 |
| size | 52,794 |
Project Name: motogarage_parser Description: A parser and interpreter for MotoGarage DSL, a language for managing motorcycle collections. Crates.io link : https://crates.io/crates/MotoGarage_parser Docs link : https://docs.rs/MotoGarage_parser/0.1.5/motogarage_parser
This project implements a parser and interpreter for a custom Domain-Specific Language (DSL) designed for managing a "garage" of motorcycles.
The data processing pipeline is as follows:
The program accepts a text file (usually with a .moto extension) that contains a set of commands. There are three types of commands:
DEFINE (for adding a motorcycle)GET (for querying the collection)COUNT (for counting items in the collection)pest library with a PEG (Parsing Expression Grammars) approach.src/grammar.pest file (see full grammar below). It describes the syntax: what "atoms" (numbers, strings, identifiers) exist and how they combine into "rules" (like DEFINE, GET, COUNT, WHERE clauses, etc.).pest automatically generates a parser (MotogarageParser in src/lib.rs) that reads the input string and builds a "tree of pairs" (Pairs), which accurately reflects the code's syntax while ignoring whitespace and comments (//...).pest is generic. For practical use, we transform it into our own, strongly-typed Abstract Syntax Tree (AST).Command, Motorcycle, Query) are defined in src/lib.rs.parse_moto_file function and its helpers (parse_command, parse_definition, etc.) recursively traverse the pest tree and build a Vec<Command>.Garage struct (src/lib.rs) acts as the interpreter. It maintains the state (a Vec<Motorcycle>).Garage::execute method iterates over the AST (Vec<Command>):
Command::Definition, it adds a new Motorcycle object to the internal list.Command::Get, it calls the filtering logic (run_query_get), which checks the motorcycles against the query conditions and returns a list of names.Command::Count, it calls the filtering logic (filter_bikes), counts the results, and returns a string with the total (e.g., "Bikes found: 2").src/main.rs) uses clap to parse CLI arguments.motogarage_parser::parse_moto_file, receives the AST, passes the AST to Garage::execute, and prints the results returned by the interpreter (or any errors that occurred).To compile and run the project:
# Ensure the code is formatted
cargo fmt
# Check the code for lints and style
cargo clippy
# Build the binary (in release mode)
cargo build --release
# Use `cargo run --` to run during development
# 1. Run the parser on a file 'my_garage1.moto':
# There are 'my_garage2.moto' and 'my_garage3.moto'with different results to show parser work
cargo run -- parse my_garage1.moto
# 2. Display help
cargo run -- --help
cargo run -- parse --help
# 3. Display credits
cargo run -- credits
Сomplete grammar used by the parser:
/// Ignores whitespace, tabs, and newlines
WHITESPACE = _{ " " | "\t" | "\n" | "\r" | line_comment }
/// Ignores single-line comments (from // to end of line)
line_comment = _{ "//" ~ (!"\n" ~ ANY)* }
// --- Top-Level Rules ---
/// A file is a Start of Input (SOI), followed by zero or more commands,
/// and ending with an End of Input (EOI).
file = { SOI ~ (command)* ~ EOI }
/// A command is either a definition (DEFINE), a GET query, or a COUNT query.
command = { definition | query_get | query_count }
// --- 1. Definition (DEFINE) Rules ---
/// Defines a new bike.
/// Example: DEFINE bike "Honda CBR" { year: 2021 }
definition = { "DEFINE" ~ "bike" ~ string_literal ~ "{" ~ properties ~ "}" }
/// A list of one or more properties, separated by commas.
properties = { property ~ ("," ~ property)* }
/// A single 'key: value' pair.
/// Example: year: 2021
property = { ident ~ ":" ~ value }
// --- 2. Query Rules ---
/// A 'GET BIKES' query, which can have an optional 'WHERE' clause.
query_get = { "GET" ~ "BIKES" ~ (where_clause)? }
/// A 'COUNT BIKES' query, which can have an optional 'WHERE' clause.
query_count = { "COUNT" ~ "BIKES" ~ (where_clause)? }
/// An optional 'WHERE' clause containing a single condition.
where_clause = { "WHERE" ~ condition }
/// A filter condition 'key <operator> value'.
/// Example: type = sport
condition = { ident ~ operator ~ value }
/// A comparison operator.
operator = { "=" | ">" | "<" }
// --- Basic Building Blocks (Atoms) ---
/// An identifier (a field name or type).
/// Starts with a letter or '_', followed by letters, numbers, or '_'.
ident = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
/// A value, which can be a number with unit (cc), a plain number,
/// a quoted string, or an identifier (like 'sport').
value = { number_with_unit | number | string_literal | ident }
/// A string of text in double quotes.
/// Example: "Honda CBR600RR"
string_literal = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
/// An integer.
/// Example: 2021
number = @{ ASCII_DIGIT+ }
/// A number with a 'cc' suffix (for engine displacement).
/// Example: 599cc
number_with_unit = @{ number ~ "cc" }
This is the most important command to run before committing new code.
make check
Runs the full quality-check suite. It executes fmt, clippy, and test all in one go.make run ARGS="..."
Runs the program in debug mode (for development).
Important: You must provide the ARGS variable to pass arguments to the program.
Examples:
# Run the parser on a file
make run ARGS="parse my_garage1.moto"
# Show the credits
make run ARGS="credits"
make build
Builds the final, optimized release version of the program. The executable will be located at target/release/moto. This is also the default command if you just run make.
make test
Runs all unit and integration tests in the project.
make fmt
Formats all Rust code according to the project's style (using cargo fmt).
make clippy
Runs the Clippy linter to check for common mistakes and un-idiomatic code. This command treats all warnings as errors (-D warnings), forcing you to write clean code.
make doc
Generates all project documentation from /// comments (including those in src/grammar.pest) and automatically opens the result in your web browser.
make clean
Removes the target directory, deleting all build artifacts, cached dependencies, and compiled executables.