Status: Alpha - Active development, APIs may change
A Rust-based parser and tooling for SysML v2 (Systems Modeling Language) and KerML (Kernel Modeling Language).
Syster is organized as a Cargo workspace with three crates:
- syster-base - Core library with parser, AST, and semantic analysis
- syster-cli - Command-line tool for analyzing SysML/KerML files
- syster-lsp - Language Server Protocol implementation (in progress)
- ARCHITECTURE.md ⭐ Core patterns and rules (start here)
- docs/CONTRIBUTING.md - Development workflow
- docs/SYSML_PRIMER.md - SysML v2 concepts for humans
Syster provides a comprehensive implementation of parsers and Abstract Syntax Trees (AST) for both SysML v2 and its foundation language KerML. The project follows a three-layer architecture:
- Parse Layer - Grammar-based parsing using Pest
- Syntax Layer - Language-specific Abstract Syntax Trees (AST)
- Model Layer - Semantic model representation (planned)
- Symbol Table: Cross-file symbol resolution with qualified names
- Import Resolution:
- Namespace imports (
import Package::*) - Member imports (
import Package::Member) - Recursive imports (
import Package::*::**) - Alias support (
alias NewName for Target)
- Namespace imports (
- Relationship Graph: Tracks specialization, typing, subsetting, redefinition, and satisfaction
- Workspace Management: Multi-file projects with shared symbol table
- Standard Library Support: Optional stdlib loading via
Workspace::with_stdlib()
- Complete grammar implementation for Kernel Modeling Language
- AST representations for all classifier types:
- Type, Classifier, DataType, Class, Structure, Behavior, Function
- Association, AssociationStructure, Metaclass
- Feature support with modifiers (readonly, derived, abstract)
- Direction qualifiers (in, out, inout)
- Package and namespace management
- Import and annotation support
- Comprehensive test coverage (28 tests)
- Grammar implementation for Systems Modeling Language v2
- AST representations for all definition types:
- Part, Port, Action, Item, Attribute, Requirement
- Concern, Case, AnalysisCase, VerificationCase, UseCase
- View, Viewpoint, Rendering
- Usage types for all major elements
- Package, comment, and import support
- Visitor pattern for AST traversal
- Comprehensive test coverage (29 tests)
crates/
├── syster-base/ # Core library
│ ├── src/
│ │ ├── core/ # Shared infrastructure
│ │ │ ├── traits.rs # AstNode, Named, ToSource traits
│ │ │ └── visitor.rs # Visitor pattern implementation
│ │ ├── language/
│ │ │ ├── kerml/
│ │ │ │ ├── syntax/ # KerML-specific AST
│ │ │ │ └── model/ # Semantic model (planned)
│ │ │ └── sysml/
│ │ │ ├── syntax/ # SysML-specific AST
│ │ │ └── model/ # Semantic model (planned)
│ │ ├── parser/
│ │ │ ├── kerml.pest # KerML grammar
│ │ │ └── sysml.pest # SysML grammar
│ │ ├── semantic/ # Cross-file analysis
│ │ │ ├── symbol_table.rs
│ │ │ ├── graph.rs
│ │ │ ├── resolver.rs
│ │ │ └── workspace.rs
│ │ └── project/ # Workspace loading
│ │ ├── workspace_loader.rs
│ │ └── stdlib_loader.rs
│ └── sysml.library/ # Standard library
├── syster-cli/ # Command-line tool
│ ├── src/
│ │ ├── main.rs # CLI entry point
│ │ └── lib.rs # Testable analysis logic
│ └── tests/
│ └── cli_tests.rs # Integration tests
└── syster-lsp/ # LSP server (in progress)
└── src/
└── main.rs
# Build all crates
cargo build
# Build specific crate
cargo build -p syster-base
cargo build -p syster-cli
cargo build -p syster-lspThe syster CLI tool analyzes SysML and KerML files:
# Analyze a single file
syster my_model.sysml
# Analyze a directory (recursive)
syster src/models/
# Verbose output
syster --verbose my_model.sysml
# Skip standard library
syster --no-stdlib my_model.sysml
# Use custom standard library
syster --stdlib-path ./custom_stdlib my_model.sysml--verbose, -v- Enable verbose output--no-stdlib- Skip loading the standard library--stdlib-path <PATH>- Path to custom standard library (default:sysml.library)
use syster::parser::{SysMLParser, sysml::Rule};
use syster::language::sysml::syntax::SysMLFile;
use syster::semantic::Workspace;
use from_pest::FromPest;
use pest::Parser;
// Parse a SysML file
let source = r#"
package MyPackage {
part def Vehicle;
}
"#;
let mut pairs = SysMLParser::parse(Rule::model, source).unwrap();
let file = SysMLFile::from_pest(&mut pairs).unwrap();
// Create a workspace (without stdlib for tests, with stdlib for real projects)
let mut workspace = Workspace::new();
workspace.add_file("example.sysml".into(), file);
workspace.populate_all().unwrap();
// Look up symbols
let vehicle = workspace.symbol_table().lookup_qualified("MyPackage::Vehicle");For real projects, load the standard library once at startup, then load project files on demand:
use syster::semantic::Workspace;
use syster::project::{StdLibLoader, WorkspaceLoader};
// Create workspace
let mut workspace = Workspace::new();
// Load standard library once at startup (from sysml.library/)
let stdlib_loader = StdLibLoader::new();
stdlib_loader.load(&mut workspace).unwrap();
// Load project files on demand
let workspace_loader = WorkspaceLoader::new();
workspace_loader.load_file("my_model.sysml", &mut workspace).unwrap();
// Or load an entire directory
workspace_loader.load_directory("src/models", &mut workspace).unwrap();
// Populate symbols and resolve references
workspace.populate_all().unwrap();
// Now query the symbol table
let symbol = workspace.symbol_table().lookup_qualified("MyPackage::MyElement");StdLibLoader - Load once at startup from sysml.library/
WorkspaceLoader - Load project files on demand as they're opened or referenced
let source = r#"
package Base {
part def Vehicle;
}
package Derived {
// Namespace import - imports all members
public import Base::*;
// Member import - imports specific member
import Base::Vehicle;
// Use imported types
part myCar : Vehicle;
}
"#;Run all tests:
cargo testRun tests for specific crate:
cargo test -p syster-base
cargo test -p syster-cli
cargo test -p syster-lspRun tests for specific module:
cargo test -p syster-base language::kerml::syntax::tests
cargo test -p syster-base language::sysml::syntax::tests
cargo test -p syster-base semanticSee docs/CONTRIBUTING.md for full guidelines. Key points:
- Test-Driven Development: Write tests first, then implement
- One function at a time: Complete full TDD cycle before moving to next function
- Format & Lint: Run
make run-guidelinesbefore committing - Small commits: Commit after each completed todo with descriptive messages
- Language-Specific AST: Each language (KerML, SysML) has its own syntax module with specific node types
- Shared Core: Common traits and patterns are defined in
src/core/ - Macro-Based FromPest: Uses
impl_from_pest!macro to reduce boilerplate in CST→AST conversion - Recursive Name Finding: Handles various grammar patterns for extracting identifications
- Grammar rules use named markers (e.g.,
abstract_marker) instead of string literals to expose them in the parse tree - This allows AST layer to properly extract flags like
is_abstract,is_readonly, etc.
When adding new AST node types:
- Define the type in
types.rs - Add enum variants in
enums.rsif needed - Implement
FromPestinast.rsusing theimpl_from_pest!macro - Add comprehensive unit tests in
tests.rs - Update the
Elementenum to handle the new type
[Add license information]