use super::lexer::Lexer;
use super::parser::{Parse, Parser, LanguageMode};
use super::grammar::{kerml, sysml};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Rule {
Package,
LibraryPackage,
Import,
Namespace,
Dependency,
Class,
DataType,
Structure,
Association,
AssociationStructure,
Behavior,
Function,
Predicate,
Interaction,
Metaclass,
Classifier,
TypeDef,
Feature,
Step,
Expression,
BooleanExpression,
Invariant,
Multiplicity,
MultiplicityRange,
Connector,
BindingConnector,
Succession,
ItemFlow,
SuccessionItemFlow,
Specialization,
Subsetting,
Redefinition,
FeatureTyping,
Conjugation,
Disjoining,
FeatureInverting,
FeatureChaining,
Subclassification,
CommentAnnotation,
Documentation,
MetadataFeature,
ParameterMembership,
ReturnParameterMembership,
OperatorExpression,
LiteralExpression,
InvocationExpression,
FeatureChainExpression,
ConditionalExpression,
QualifiedReferenceChain,
Identification,
Visibility,
NamespaceBody,
NamespaceBodyElement,
NamespaceBodyElements,
PartDef,
AttributeDef,
ItemDef,
PortDef,
ActionDef,
StateDef,
CalcDef,
ConstraintDef,
RequirementDef,
ConnectionDef,
InterfaceDef,
AllocationDef,
PartUsage,
AttributeUsage,
ItemUsage,
PortUsage,
ActionUsage,
StateUsage,
CalcUsage,
ConstraintUsage,
RequirementUsage,
ConnectionUsage,
InterfaceUsage,
AllocationUsage,
PerformActionUsage,
SendActionUsage,
AcceptActionUsage,
AssignActionUsage,
IfActionUsage,
WhileLoopActionUsage,
ForLoopActionUsage,
BindingConnectorAsUsage,
SuccessionAsUsage,
RegularName,
UnrestrictedName,
ShortName,
LiteralNumber,
KerMLFile,
SysMLFile,
}
#[derive(Debug)]
pub struct RuleParseResult {
pub parse: Parse,
pub rule: Rule,
pub input: String,
}
impl RuleParseResult {
pub fn is_ok(&self) -> bool {
self.parse.ok()
}
pub fn errors(&self) -> &[super::parser::SyntaxError] {
&self.parse.errors
}
pub fn syntax(&self) -> super::SyntaxNode {
self.parse.syntax()
}
pub fn fully_consumed(&self) -> bool {
let root = self.parse.syntax();
let tree_text = root.text().to_string();
tree_text.trim() == self.input.trim()
}
}
pub fn parse_rule(rule: Rule, input: &str) -> RuleParseResult {
let (wrapped_input, mode) = wrap_for_rule(rule, input);
let tokens: Vec<_> = Lexer::new(&wrapped_input).collect();
let mut parser = Parser::new(&tokens, mode);
match mode {
LanguageMode::KerML => kerml::parse_kerml_file(&mut parser),
LanguageMode::SysML => sysml::parse_sysml_file(&mut parser),
}
RuleParseResult {
parse: parser.finish(),
rule,
input: input.to_string(),
}
}
fn wrap_for_rule(rule: Rule, input: &str) -> (String, LanguageMode) {
match rule {
Rule::KerMLFile => (input.to_string(), LanguageMode::KerML),
Rule::SysMLFile => (input.to_string(), LanguageMode::SysML),
Rule::Package | Rule::LibraryPackage | Rule::Namespace => {
(input.to_string(), LanguageMode::KerML)
}
Rule::Import | Rule::Dependency => {
(format!("package __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::Class | Rule::DataType | Rule::Structure | Rule::Association |
Rule::AssociationStructure | Rule::Behavior | Rule::Function |
Rule::Predicate | Rule::Interaction | Rule::Metaclass |
Rule::Classifier | Rule::TypeDef => {
(format!("package __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::Feature | Rule::Step | Rule::Expression | Rule::BooleanExpression |
Rule::Invariant | Rule::Multiplicity | Rule::MultiplicityRange => {
(format!("class __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::Connector | Rule::BindingConnector | Rule::Succession |
Rule::ItemFlow | Rule::SuccessionItemFlow => {
(format!("class __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::Specialization | Rule::Subsetting | Rule::Redefinition |
Rule::FeatureTyping | Rule::Conjugation | Rule::FeatureChaining => {
(format!("class __Test__ {{ feature x {} ; }}", input), LanguageMode::KerML)
}
Rule::Disjoining => {
if input.contains("from") {
(format!("package __Test__ {{ {} }}", input), LanguageMode::KerML)
} else {
(format!("class __Test__ {{ feature x {} ; }}", input), LanguageMode::KerML)
}
}
Rule::Subclassification => {
(format!("package __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::FeatureInverting => {
(format!("package __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::CommentAnnotation | Rule::Documentation | Rule::MetadataFeature => {
(format!("package __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::ParameterMembership | Rule::ReturnParameterMembership => {
(format!("function __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::OperatorExpression | Rule::LiteralExpression |
Rule::InvocationExpression | Rule::FeatureChainExpression |
Rule::ConditionalExpression => {
(format!("class __Test__ {{ feature x = {}; }}", input), LanguageMode::KerML)
}
Rule::QualifiedReferenceChain => {
(format!("import {};", input), LanguageMode::KerML)
}
Rule::Identification => {
(format!("class {} {{}}", input), LanguageMode::KerML)
}
Rule::Visibility => {
(format!("{} class X {{}}", input), LanguageMode::KerML)
}
Rule::NamespaceBody => {
(format!("class __Test__ {}", input), LanguageMode::KerML)
}
Rule::NamespaceBodyElement | Rule::NamespaceBodyElements => {
(format!("class __Test__ {{ {} }}", input), LanguageMode::KerML)
}
Rule::PartDef | Rule::AttributeDef | Rule::ItemDef |
Rule::PortDef | Rule::ActionDef | Rule::StateDef |
Rule::CalcDef | Rule::ConstraintDef | Rule::RequirementDef |
Rule::ConnectionDef | Rule::InterfaceDef | Rule::AllocationDef => {
(format!("package __Test__ {{ {} }}", input), LanguageMode::SysML)
}
Rule::PartUsage | Rule::AttributeUsage | Rule::ItemUsage |
Rule::PortUsage | Rule::ActionUsage | Rule::StateUsage |
Rule::CalcUsage | Rule::ConstraintUsage | Rule::RequirementUsage |
Rule::ConnectionUsage | Rule::InterfaceUsage | Rule::AllocationUsage => {
(format!("part def __Test__ {{ {} }}", input), LanguageMode::SysML)
}
Rule::PerformActionUsage | Rule::SendActionUsage |
Rule::AcceptActionUsage | Rule::AssignActionUsage |
Rule::IfActionUsage | Rule::WhileLoopActionUsage |
Rule::ForLoopActionUsage => {
(format!("action def __Test__ {{ {} }}", input), LanguageMode::SysML)
}
Rule::BindingConnectorAsUsage | Rule::SuccessionAsUsage => {
(format!("part def __Test__ {{ {} }}", input), LanguageMode::SysML)
}
Rule::RegularName | Rule::UnrestrictedName => {
(format!("class {} {{}}", input), LanguageMode::KerML)
}
Rule::ShortName => {
(format!("class {} X {{}}", input), LanguageMode::KerML)
}
Rule::LiteralNumber => {
(format!("class __Test__ {{ feature x = {}; }}", input), LanguageMode::KerML)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_item_flow() {
let result = parse_rule(Rule::ItemFlow, "flow myFlow from a to b;");
assert!(result.is_ok(), "Failed to parse item_flow: {:?}", result.errors());
}
#[test]
fn test_parse_connector() {
let result = parse_rule(Rule::Connector, "connector from x to y;");
assert!(result.is_ok(), "Failed to parse connector: {:?}", result.errors());
}
#[test]
fn test_parse_class() {
let result = parse_rule(Rule::Class, "class MyClass specializes Base;");
assert!(result.is_ok(), "Failed to parse class: {:?}", result.errors());
}
#[test]
fn test_parse_feature() {
let result = parse_rule(Rule::Feature, "feature x : Integer[1];");
assert!(result.is_ok(), "Failed to parse feature: {:?}", result.errors());
}
#[test]
fn test_parse_operator_expression() {
let result = parse_rule(Rule::OperatorExpression, "a + b * c");
assert!(result.is_ok(), "Failed to parse expression: {:?}", result.errors());
}
#[test]
fn test_parse_succession() {
let result = parse_rule(Rule::Succession, "succession a then b;");
assert!(result.is_ok(), "Failed to parse succession: {:?}", result.errors());
}
}