| Crates.io | modality-lang |
| lib.rs | modality-lang |
| version | 0.1.6 |
| created_at | 2025-07-19 00:29:55.439501+00 |
| updated_at | 2025-07-19 00:29:55.439501+00 |
| description | Modality language lib |
| homepage | https://www.modality.org |
| repository | https://github.com/modality-org/modality |
| max_upload_size | |
| id | 1759818 |
| size | 1,047,995 |
This crate provides a parser for the Modality temporal logic language, specifically for parsing .modality files that contain LTS (Labeled Transition System) models.
.modality files containing model definitionsThe formal syntax of the Modality language is defined by a BNF grammar. See BNF.md for the complete Backus-Naur Form specification.
use modality_lang::{parse_file, parse_file_lalrpop};
// Parse from file using hand-written parser
let model = parse_file("path/to/model.modality")?;
// Parse from file using LALRPOP parser
let model = parse_file_lalrpop("path/to/model.modality")?;
// Parse from string content
let content = r#"
model MyModel:
graph g1:
n1 --> n2: +blue
n2 --> n3: -red
"#;
let model = parse_content(content)?;
use modality_lang::parse_all_models_lalrpop;
// Parse all models in a file using LALRPOP
let models = parse_all_models_lalrpop("path/to/models.modality")?;
for model in models {
println!("Model: {}", model.name);
}
use modality_lang::{parse_file_lalrpop, generate_mermaid_diagram, generate_mermaid_diagrams};
// Parse a model and generate a Mermaid diagram
let model = parse_file_lalrpop("path/to/model.modality")?;
let diagram = generate_mermaid_diagram(&model);
println!("{}", diagram);
// Generate diagrams for multiple models
let models = parse_all_models_lalrpop("path/to/models.modality")?;
let combined_diagrams = generate_mermaid_diagrams(&models);
println!("{}", combined_diagrams);
// Generate a styled diagram
let styled_diagram = generate_mermaid_diagram_with_styling(&model);
println!("{}", styled_diagram);
The parser supports the following syntax:
// Simple model with one transition
model InitialModel:
graph g1:
n1 --> n1
// Model with properties
model Model3:
graph g1:
n1 --> n2: +blue
n2 --> n3: +blue
// Model with multiple properties
model Model4:
graph g1:
n1 --> n2: +blue -red
n2 --> n3: +blue -green
n3 --> n1: -blue +red
// Model with multiple graphs
model Model4:
graph g1:
n1 --> n2: +blue -red
n2 --> n3: +blue -green
n3 --> n1: -blue +red
graph g2:
n1 --> n1: +yellow
src/parser.rsparse_file(), parse_content()src/grammar.lalrpop, src/lalrpop_parser.rsparse_file_lalrpop(), parse_content_lalrpop(), parse_all_models_lalrpop()generate_mermaid_diagram(model: &Model) -> Stringgenerate_mermaid_diagrams(models: &[Model]) -> Stringgenerate_mermaid_diagram_with_styling(model: &Model) -> String : +blue -red)g1.n1, g2.n1) to prevent conflictsstateDiagram-v2
state g1 {
g1.n1 : n1
g1.n2 : n2
g1.n3 : n3
g1.n1 --> g1.n2 : +blue -red
g1.n2 --> g1.n3 : +blue -green
g1.n3 --> g1.n1 : -blue +red
}
state g2 {
g2.n1 : n1
g2.n1 --> g2.n1 : +yellow
}
Note: In the above example, g1 and g2 are completely isolated graphs. States in g1 (g1.n1, g1.n2, g1.n3) cannot transition to states in g2 (g2.n1), and vice versa. Each graph represents an independent LTS (Labeled Transition System). The prefixed naming (g1.n1, g2.n1) makes the graph isolation explicit and prevents naming conflicts. Properties are space-separated in transition labels.
Represents a complete model containing multiple graphs.
pub struct Model {
pub name: String,
pub graphs: Vec<Graph>,
}
Represents a graph within a model containing transitions.
pub struct Graph {
pub name: String,
pub transitions: Vec<Transition>,
}
Represents a transition between nodes with optional properties.
pub struct Transition {
pub from: String,
pub to: String,
pub properties: Vec<Property>,
}
Represents a property with a sign (+ or -).
pub struct Property {
pub sign: PropertySign,
pub name: String,
}
pub enum PropertySign {
Plus,
Minus,
}
See the examples/ directory for working examples:
parse_example.rs - Basic parsing exampleparse_all_models.rs - Parse all models in a filecompare_parsers.rs - Compare hand-written vs LALRPOP parserslalrpop_example.rs - LALRPOP parser with multiple modelsmermaid_example.rs - Mermaid diagram generationRun examples with:
cargo run --example parse_example
cargo run --example parse_all_models
cargo run --example compare_parsers
cargo run --example lalrpop_example
cargo run --example mermaid_example
The LALRPOP grammar (src/grammar.lalrpop) defines the syntax:
Model: Model = {
<model:ModelDecl> => model
};
ModelDecl: Model = {
"model" <name:Ident> ":" <graphs:Graph*> => { ... }
};
Graph: Graph = {
"graph" <name:Ident> ":" <transitions:Transition*> => { ... }
};
Transition: Transition = {
<from:Ident> "-->" <to:Ident> => { ... },
<from:Ident> "-->" <to:Ident> ":" <properties:PropertyList> => { ... }
};
PropertyList: Vec<Property> = {
<property:Property> => vec![property],
<properties:PropertyList> <property:Property> => { ... }
};
Property: Property = {
"+" <name:Ident> => Property::new(PropertySign::Plus, name),
"-" <name:Ident> => Property::new(PropertySign::Minus, name)
};
The parser returns Result<Model, String> where errors are descriptive strings indicating what went wrong during parsing.
Common error cases:
The LALRPOP parser is automatically generated during the build process. The build script (build.rs) handles the grammar compilation.