use super::kerml_expressions::ExpressionParser;
use crate::parser::parser::kind_to_name;
use crate::parser::syntax_kind::SyntaxKind;
pub const KERML_DEFINITION_KEYWORDS: &[SyntaxKind] = &[
SyntaxKind::CLASS_KW,
SyntaxKind::STRUCT_KW,
SyntaxKind::DATATYPE_KW,
SyntaxKind::BEHAVIOR_KW,
SyntaxKind::FUNCTION_KW,
SyntaxKind::CLASSIFIER_KW,
SyntaxKind::INTERACTION_KW,
SyntaxKind::PREDICATE_KW,
SyntaxKind::METACLASS_KW,
SyntaxKind::ASSOC_KW,
];
pub const KERML_USAGE_KEYWORDS: &[SyntaxKind] = &[
SyntaxKind::FEATURE_KW,
SyntaxKind::STEP_KW,
SyntaxKind::EXPR_KW,
];
pub const FEATURE_PREFIX_MODIFIERS: &[SyntaxKind] = &[
SyntaxKind::VAR_KW,
SyntaxKind::COMPOSITE_KW,
SyntaxKind::PORTION_KW,
SyntaxKind::MEMBER_KW,
SyntaxKind::ABSTRACT_KW,
SyntaxKind::DERIVED_KW,
SyntaxKind::CONST_KW,
SyntaxKind::END_KW,
];
pub const DEFINITION_PREFIXES: &[SyntaxKind] = &[SyntaxKind::ABSTRACT_KW, SyntaxKind::VARIATION_KW];
pub const STANDALONE_RELATIONSHIP_KEYWORDS: &[SyntaxKind] = &[
SyntaxKind::SPECIALIZATION_KW,
SyntaxKind::SUBCLASSIFIER_KW,
SyntaxKind::REDEFINITION_KW,
SyntaxKind::SUBSET_KW,
SyntaxKind::SUBTYPE_KW,
SyntaxKind::TYPING_KW,
SyntaxKind::CONJUGATION_KW,
SyntaxKind::DISJOINING_KW,
SyntaxKind::FEATURING_KW,
SyntaxKind::INVERTING_KW,
];
pub const RELATIONSHIP_OPERATORS: &[SyntaxKind] = &[
SyntaxKind::SPECIALIZES_KW,
SyntaxKind::COLON_GT,
SyntaxKind::SUBSETS_KW,
SyntaxKind::REDEFINES_KW,
SyntaxKind::COLON_GT_GT,
SyntaxKind::TYPED_KW,
SyntaxKind::COLON,
SyntaxKind::CONJUGATES_KW,
SyntaxKind::TILDE,
SyntaxKind::INVERSE_KW,
SyntaxKind::OF_KW,
];
pub fn is_kerml_definition_keyword(kind: SyntaxKind) -> bool {
KERML_DEFINITION_KEYWORDS.contains(&kind)
}
pub fn is_kerml_usage_keyword(kind: SyntaxKind) -> bool {
KERML_USAGE_KEYWORDS.contains(&kind)
}
pub fn is_feature_prefix_modifier(kind: SyntaxKind) -> bool {
FEATURE_PREFIX_MODIFIERS.contains(&kind)
}
pub fn is_standalone_relationship_keyword(kind: SyntaxKind) -> bool {
STANDALONE_RELATIONSHIP_KEYWORDS.contains(&kind)
}
pub trait KerMLParser: ExpressionParser {
fn current_token_text(&self) -> Option<&str>;
fn parse_identification(&mut self);
fn parse_body(&mut self);
fn skip_trivia_except_block_comments(&mut self);
fn parse_qualified_name_list(&mut self);
fn parse_namespace_member(&mut self)
where
Self: Sized,
{
parse_namespace_element(self);
}
fn parse_package(&mut self);
fn parse_library_package(&mut self);
fn parse_import(&mut self);
fn parse_alias(&mut self);
fn parse_definition(&mut self);
fn parse_usage(&mut self);
fn parse_invariant(&mut self);
fn parse_parameter(&mut self);
fn parse_end_feature_or_parameter(&mut self);
fn parse_connector_usage(&mut self);
fn parse_flow_usage(&mut self);
fn error(&mut self, message: impl Into<String>);
fn error_recover(&mut self, message: impl Into<String>, recovery: &[SyntaxKind]);
}
fn error_missing_body_terminator<P: KerMLParser>(p: &mut P, context: &str) {
let found = if let Some(text) = p.current_token_text() {
format!("'{}' ({})", text, kind_to_name(p.current_kind()))
} else {
"end of file".to_string()
};
p.error(format!(
"expected ';' to end {} or '{{' to start body, found {}",
context, found
));
}
#[inline]
fn bump_and_skip<P: KerMLParser>(p: &mut P) {
p.bump();
p.skip_trivia();
}
#[inline]
fn expect_and_skip<P: KerMLParser>(p: &mut P, kind: SyntaxKind) {
p.expect(kind);
p.skip_trivia();
}
#[inline]
fn consume_if<P: KerMLParser>(p: &mut P, kind: SyntaxKind) -> bool {
if p.at(kind) {
p.bump();
p.skip_trivia();
true
} else {
false
}
}
#[inline]
fn parse_qualified_name_and_skip<P: KerMLParser>(p: &mut P) {
p.parse_qualified_name();
p.skip_trivia();
}
#[inline]
fn parse_identification_and_skip<P: KerMLParser>(p: &mut P) {
p.parse_identification();
p.skip_trivia();
}
fn parse_optional_identification<P: KerMLParser>(p: &mut P) {
if p.at_name_token() || p.at(SyntaxKind::LT) {
p.parse_identification();
p.skip_trivia();
}
}
fn parse_optional_qualified_name<P: KerMLParser>(p: &mut P) {
if p.at_name_token() || p.at(SyntaxKind::THIS_KW) {
p.parse_qualified_name();
p.skip_trivia();
}
}
#[inline]
fn parse_optional_visibility<P: KerMLParser>(p: &mut P) {
if p.at_any(&[
SyntaxKind::PUBLIC_KW,
SyntaxKind::PRIVATE_KW,
SyntaxKind::PROTECTED_KW,
]) {
bump_and_skip(p);
}
}
fn parse_optional_multiplicity<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
}
fn parse_optional_typing<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::COLON) || p.at(SyntaxKind::TYPED_KW) || p.at(SyntaxKind::OF_KW) {
parse_typing(p);
p.skip_trivia();
}
}
fn parse_comma_separated_names<P: KerMLParser>(p: &mut P) {
parse_qualified_name_and_skip(p);
while p.at(SyntaxKind::COMMA) {
bump_and_skip(p);
if p.at_name_token() {
parse_qualified_name_and_skip(p);
}
}
}
fn looks_like_qualified_name_before<P: KerMLParser>(p: &P, target_kinds: &[SyntaxKind]) -> bool {
if !p.at_name_token() {
return false;
}
let mut peek_idx = 1;
let mut has_qualifier = false;
loop {
let mut kind = p.peek_kind(peek_idx);
while kind.is_trivia() {
peek_idx += 1;
kind = p.peek_kind(peek_idx);
}
if kind == SyntaxKind::DOT || kind == SyntaxKind::COLON_COLON {
has_qualifier = true;
peek_idx += 1;
kind = p.peek_kind(peek_idx);
while kind.is_trivia() {
peek_idx += 1;
kind = p.peek_kind(peek_idx);
}
if is_name_kind(kind) {
peek_idx += 1;
continue;
} else {
return false;
}
} else if target_kinds.contains(&kind) {
return has_qualifier;
} else {
return false;
}
}
}
fn looks_like_name_then<P: KerMLParser>(p: &P, target_kind: SyntaxKind) -> bool {
if !p.at_name_token() {
return false;
}
let mut peek_idx = 1;
loop {
let mut kind = p.peek_kind(peek_idx);
while kind.is_trivia() {
peek_idx += 1;
kind = p.peek_kind(peek_idx);
}
if kind == SyntaxKind::DOT || kind == SyntaxKind::COLON_COLON {
peek_idx += 1;
kind = p.peek_kind(peek_idx);
while kind.is_trivia() {
peek_idx += 1;
kind = p.peek_kind(peek_idx);
}
if is_name_kind(kind) {
peek_idx += 1;
continue;
} else {
return false;
}
} else if kind == target_kind {
return true;
} else {
return false;
}
}
}
pub fn parse_kerml_file<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::SOURCE_FILE);
while !p.at(SyntaxKind::ERROR) {
p.skip_trivia();
if p.at(SyntaxKind::ERROR) {
break;
}
let start_pos = p.get_pos();
parse_namespace_element(p);
if p.get_pos() == start_pos {
let got = if p.at(SyntaxKind::ERROR) {
"end of file".to_string()
} else if let Some(text) = p.current_token_text() {
format!("'{}'", text)
} else {
kind_to_name(p.current_kind()).to_string()
};
p.error(format!("unexpected {} in top level", got));
p.bump();
}
}
p.finish_node();
}
pub fn parse_namespace_element<P: KerMLParser>(p: &mut P) {
p.skip_trivia();
if p.at_any(&[
SyntaxKind::PUBLIC_KW,
SyntaxKind::PRIVATE_KW,
SyntaxKind::PROTECTED_KW,
]) {
bump_and_skip(p);
}
while p.at(SyntaxKind::HASH) {
parse_prefix_metadata(p);
p.skip_trivia();
}
match p.current_kind() {
SyntaxKind::PACKAGE_KW | SyntaxKind::NAMESPACE_KW => p.parse_package(),
SyntaxKind::LIBRARY_KW | SyntaxKind::STANDARD_KW => p.parse_library_package(),
SyntaxKind::IMPORT_KW => p.parse_import(),
SyntaxKind::ALIAS_KW => p.parse_alias(),
SyntaxKind::COMMENT_KW
| SyntaxKind::DOC_KW
| SyntaxKind::LOCALE_KW
| SyntaxKind::AT
| SyntaxKind::AT_AT
| SyntaxKind::METADATA_KW => parse_annotation(p),
SyntaxKind::CLASS_KW
| SyntaxKind::STRUCT_KW
| SyntaxKind::DATATYPE_KW
| SyntaxKind::BEHAVIOR_KW
| SyntaxKind::FUNCTION_KW
| SyntaxKind::ASSOC_KW
| SyntaxKind::CLASSIFIER_KW
| SyntaxKind::INTERACTION_KW
| SyntaxKind::PREDICATE_KW
| SyntaxKind::METACLASS_KW
| SyntaxKind::TYPE_KW => p.parse_definition(),
SyntaxKind::ABSTRACT_KW => handle_abstract_prefix(p),
SyntaxKind::FEATURE_KW | SyntaxKind::STEP_KW | SyntaxKind::EXPR_KW => p.parse_usage(),
SyntaxKind::INV_KW => p.parse_invariant(),
SyntaxKind::REP_KW | SyntaxKind::LANGUAGE_KW => parse_textual_representation(p),
SyntaxKind::IN_KW | SyntaxKind::OUT_KW | SyntaxKind::INOUT_KW | SyntaxKind::RETURN_KW => {
p.parse_parameter()
}
SyntaxKind::END_KW => p.parse_end_feature_or_parameter(),
SyntaxKind::CONST_KW => handle_const_prefix(p),
SyntaxKind::CONNECTOR_KW | SyntaxKind::BINDING_KW => p.parse_connector_usage(),
SyntaxKind::SUCCESSION_KW | SyntaxKind::FIRST_KW => handle_succession_prefix(p),
SyntaxKind::FLOW_KW => p.parse_flow_usage(),
SyntaxKind::MULTIPLICITY_KW => parse_multiplicity_definition(p),
SyntaxKind::SPECIALIZATION_KW
| SyntaxKind::SUBCLASSIFIER_KW
| SyntaxKind::REDEFINITION_KW
| SyntaxKind::SUBSET_KW
| SyntaxKind::TYPING_KW
| SyntaxKind::CONJUGATION_KW
| SyntaxKind::CONJUGATE_KW
| SyntaxKind::DISJOINING_KW
| SyntaxKind::FEATURING_KW
| SyntaxKind::SUBTYPE_KW => parse_standalone_relationship(p),
SyntaxKind::INVERTING_KW | SyntaxKind::INVERSE_KW => parse_inverting_relationship(p),
SyntaxKind::DEPENDENCY_KW => parse_dependency(p),
SyntaxKind::DISJOINT_KW => parse_disjoint(p),
SyntaxKind::FILTER_KW => parse_filter(p),
SyntaxKind::REDEFINES_KW
| SyntaxKind::COLON_GT_GT
| SyntaxKind::SUBSETS_KW
| SyntaxKind::COLON_GT => p.parse_usage(),
SyntaxKind::VAR_KW
| SyntaxKind::REF_KW
| SyntaxKind::COMPOSITE_KW
| SyntaxKind::PORTION_KW
| SyntaxKind::MEMBER_KW
| SyntaxKind::DERIVED_KW
| SyntaxKind::READONLY_KW => {
handle_feature_modifier_prefix(p);
}
SyntaxKind::IDENT => p.parse_usage(),
SyntaxKind::NOT_KW
| SyntaxKind::TRUE_KW
| SyntaxKind::FALSE_KW
| SyntaxKind::NULL_KW
| SyntaxKind::IF_KW
| SyntaxKind::INTEGER
| SyntaxKind::DECIMAL
| SyntaxKind::STRING
| SyntaxKind::L_PAREN => {
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
}
}
_ => {
let got = if let Some(text) = p.current_token_text() {
format!("'{}'", text)
} else {
kind_to_name(p.current_kind()).to_string()
};
p.error_recover(
format!("unexpected {} in namespace body", got),
&[
SyntaxKind::PACKAGE_KW,
SyntaxKind::CLASS_KW,
SyntaxKind::R_BRACE,
],
);
}
}
}
fn parse_prefix_metadata<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::PREFIX_METADATA);
expect_and_skip(p, SyntaxKind::HASH);
if p.at_name_token() {
p.bump();
}
p.finish_node();
}
fn handle_abstract_prefix<P: KerMLParser>(p: &mut P) {
let next = p.peek_kind(1);
if matches!(
next,
SyntaxKind::CLASS_KW
| SyntaxKind::STRUCT_KW
| SyntaxKind::DATATYPE_KW
| SyntaxKind::BEHAVIOR_KW
| SyntaxKind::FUNCTION_KW
| SyntaxKind::ASSOC_KW
| SyntaxKind::CLASSIFIER_KW
| SyntaxKind::PREDICATE_KW
| SyntaxKind::METACLASS_KW
| SyntaxKind::INTERACTION_KW
| SyntaxKind::TYPE_KW
) {
p.parse_definition();
} else if next == SyntaxKind::FLOW_KW {
p.parse_flow_usage();
} else if matches!(
next,
SyntaxKind::CONNECTOR_KW | SyntaxKind::BINDING_KW | SyntaxKind::SUCCESSION_KW
) {
p.parse_connector_usage();
} else {
p.parse_usage();
}
}
fn handle_const_prefix<P: KerMLParser>(p: &mut P) {
let next = p.peek_kind(1);
if next == SyntaxKind::END_KW {
p.parse_end_feature_or_parameter();
} else {
p.parse_usage();
}
}
fn handle_feature_modifier_prefix<P: KerMLParser>(p: &mut P) {
let next = p.peek_kind(1);
if matches!(
next,
SyntaxKind::CONNECTOR_KW | SyntaxKind::BINDING_KW | SyntaxKind::SUCCESSION_KW
) {
p.parse_connector_usage();
} else {
p.parse_usage();
}
}
fn handle_succession_prefix<P: KerMLParser>(p: &mut P) {
let next = p.peek_kind(1);
if next == SyntaxKind::FLOW_KW {
p.parse_flow_usage();
} else {
p.parse_connector_usage();
}
}
fn parse_featuring_relationship<P: KerMLParser>(p: &mut P) {
bump_and_skip(p);
if p.at_name_token() {
parse_identification_and_skip(p);
if p.at(SyntaxKind::OF_KW) {
bump_and_skip(p);
parse_optional_qualified_name(p);
}
}
if p.at(SyntaxKind::BY_KW) {
bump_and_skip(p);
parse_optional_qualified_name(p);
}
}
fn parse_typing_relationship<P: KerMLParser>(p: &mut P) {
bump_and_skip(p);
parse_optional_qualified_name(p);
if p.at(SyntaxKind::COLON) || p.at(SyntaxKind::TYPED_KW) {
parse_typing(p);
}
}
fn parse_conjugation_relationship<P: KerMLParser>(p: &mut P) {
let is_shorthand = p.at(SyntaxKind::CONJUGATE_KW);
bump_and_skip(p);
if is_shorthand {
parse_optional_qualified_name(p);
if p.at(SyntaxKind::CONJUGATES_KW) || p.at(SyntaxKind::TILDE) {
bump_and_skip(p);
}
parse_optional_qualified_name(p);
} else {
if p.at_name_token() && !p.at(SyntaxKind::CONJUGATE_KW) {
parse_identification_and_skip(p);
}
consume_if(p, SyntaxKind::CONJUGATE_KW);
parse_optional_qualified_name(p);
if p.at(SyntaxKind::CONJUGATES_KW) || p.at(SyntaxKind::TILDE) {
bump_and_skip(p);
}
parse_optional_qualified_name(p);
}
}
fn parse_generic_relationship<P: KerMLParser>(p: &mut P) {
if p.at_any(STANDALONE_RELATIONSHIP_KEYWORDS) {
bump_and_skip(p);
}
parse_optional_qualified_name(p);
if p.at_any(RELATIONSHIP_OPERATORS) {
bump_and_skip(p);
}
parse_optional_qualified_name(p);
}
pub fn parse_standalone_relationship<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::RELATIONSHIP);
if p.at(SyntaxKind::SPECIALIZATION_KW) {
bump_and_skip(p);
if p.at_name_token()
&& !p.at_any(&[
SyntaxKind::SUBCLASSIFIER_KW,
SyntaxKind::SUBTYPE_KW,
SyntaxKind::SUBSET_KW,
SyntaxKind::REDEFINITION_KW,
SyntaxKind::TYPING_KW,
])
{
parse_identification_and_skip(p);
}
}
if p.at(SyntaxKind::FEATURING_KW) {
parse_featuring_relationship(p);
} else if p.at(SyntaxKind::TYPING_KW) {
parse_typing_relationship(p);
} else if p.at(SyntaxKind::CONJUGATION_KW) || p.at(SyntaxKind::CONJUGATE_KW) {
parse_conjugation_relationship(p);
} else {
parse_generic_relationship(p);
}
p.parse_body();
p.finish_node();
}
pub fn parse_dependency<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::DEPENDENCY);
expect_and_skip(p, SyntaxKind::DEPENDENCY_KW);
if p.at(SyntaxKind::FROM_KW) {
bump_and_skip(p);
} else if p.at(SyntaxKind::LT) {
parse_identification_and_skip(p);
if p.at(SyntaxKind::FROM_KW) {
bump_and_skip(p);
}
} else if p.at_name_token() && !p.at(SyntaxKind::TO_KW) {
let peek1 = p.peek_kind(1);
let peek2 = p.peek_kind(2);
if peek1 == SyntaxKind::FROM_KW || peek2 == SyntaxKind::FROM_KW {
parse_identification_and_skip(p);
if p.at(SyntaxKind::FROM_KW) {
bump_and_skip(p);
}
}
}
if p.at_name_token() && !p.at(SyntaxKind::TO_KW) {
parse_comma_separated_names(p);
}
expect_and_skip(p, SyntaxKind::TO_KW);
if p.at_name_token() {
parse_comma_separated_names(p);
}
p.parse_body();
p.finish_node();
}
pub fn parse_textual_representation<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::TEXTUAL_REP);
if p.at(SyntaxKind::REP_KW) {
bump_and_skip(p);
if p.at_name_token() || p.at(SyntaxKind::LT) {
parse_identification_and_skip(p);
}
}
expect_and_skip(p, SyntaxKind::LANGUAGE_KW);
expect_and_skip(p, SyntaxKind::STRING);
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
}
p.finish_node();
}
pub fn parse_disjoint<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::RELATIONSHIP);
expect_and_skip(p, SyntaxKind::DISJOINT_KW);
if p.at_name_token() {
parse_feature_chain_or_qualified_name(p);
}
if p.at(SyntaxKind::FROM_KW) {
bump_and_skip(p);
if p.at_name_token() {
parse_feature_chain_or_qualified_name(p);
}
}
p.parse_body();
p.finish_node();
}
fn parse_feature_chain_or_qualified_name<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::QUALIFIED_NAME);
if p.at_name_token() {
p.bump();
}
p.skip_trivia();
while p.at(SyntaxKind::COLON_COLON) || p.at(SyntaxKind::DOT) {
p.bump(); p.skip_trivia();
if p.at_name_token() {
p.bump();
}
p.skip_trivia();
}
p.finish_node();
p.skip_trivia();
}
pub fn parse_filter<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::ELEMENT_FILTER_MEMBER);
expect_and_skip(p, SyntaxKind::FILTER_KW);
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
p.expect(SyntaxKind::SEMICOLON);
p.finish_node();
}
pub fn parse_inverting_relationship<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::RELATIONSHIP);
if p.at(SyntaxKind::INVERTING_KW) {
bump_and_skip(p);
if p.at_name_token() && !p.at(SyntaxKind::INVERSE_KW) {
parse_identification_and_skip(p);
}
}
expect_and_skip(p, SyntaxKind::INVERSE_KW);
parse_optional_qualified_name(p);
expect_and_skip(p, SyntaxKind::OF_KW);
parse_optional_qualified_name(p);
p.parse_body();
p.finish_node();
}
fn parse_metadata_annotation<P: KerMLParser>(p: &mut P) {
bump_and_skip(p);
if p.at_name_token()
&& p.peek_kind(1) != SyntaxKind::SEMICOLON
&& p.peek_kind(1) != SyntaxKind::L_BRACE
&& matches!(p.peek_kind(1), SyntaxKind::COLON | SyntaxKind::TYPED_KW)
{
parse_identification_and_skip(p);
bump_and_skip(p); consume_if(p, SyntaxKind::BY_KW);
}
parse_optional_qualified_name(p);
if p.at(SyntaxKind::ABOUT_KW) {
bump_and_skip(p);
p.parse_qualified_name_list();
p.skip_trivia();
}
if p.at(SyntaxKind::L_BRACE) {
parse_annotation_body(p);
} else if p.at(SyntaxKind::SEMICOLON) {
p.bump();
}
}
fn parse_locale_annotation<P: KerMLParser>(p: &mut P) {
p.bump(); p.skip_trivia_except_block_comments();
if p.at(SyntaxKind::STRING) {
p.bump();
p.skip_trivia_except_block_comments();
}
if p.at(SyntaxKind::BLOCK_COMMENT) {
p.bump();
}
}
fn check_block_comment<P: KerMLParser>(p: &mut P) -> bool {
if p.at(SyntaxKind::BLOCK_COMMENT) {
p.bump();
true
} else {
false
}
}
fn parse_locale_clause<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::LOCALE_KW) {
p.bump();
p.skip_trivia_except_block_comments();
if p.at(SyntaxKind::STRING) {
p.bump();
p.skip_trivia_except_block_comments();
}
}
}
fn parse_about_clause<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::ABOUT_KW) {
p.bump();
p.skip_trivia();
p.parse_qualified_name_list();
p.skip_trivia_except_block_comments();
parse_locale_clause(p);
}
}
fn parse_comment_doc_annotation<P: KerMLParser>(p: &mut P) {
p.skip_trivia_except_block_comments();
if check_block_comment(p) {
return;
}
if (p.at_name_token() || p.at(SyntaxKind::LT))
&& !p.at(SyntaxKind::ABOUT_KW)
&& !p.at(SyntaxKind::LOCALE_KW)
{
p.parse_identification();
p.skip_trivia_except_block_comments();
if check_block_comment(p) {
return;
}
}
parse_locale_clause(p);
if check_block_comment(p) {
return;
}
parse_about_clause(p);
if check_block_comment(p) {
return;
}
if p.at(SyntaxKind::L_BRACE) {
parse_annotation_body(p);
} else if p.at(SyntaxKind::SEMICOLON) {
p.bump();
}
}
pub fn parse_annotation<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::COMMENT_ELEMENT);
if p.at(SyntaxKind::AT) || p.at(SyntaxKind::AT_AT) || p.at(SyntaxKind::METADATA_KW) {
parse_metadata_annotation(p);
} else if p.at(SyntaxKind::LOCALE_KW) {
parse_locale_annotation(p);
} else {
if p.at(SyntaxKind::COMMENT_KW) || p.at(SyntaxKind::DOC_KW) {
p.bump();
}
parse_comment_doc_annotation(p);
}
p.finish_node();
}
fn parse_annotation_body<P: KerMLParser>(p: &mut P) {
p.expect(SyntaxKind::L_BRACE);
p.skip_trivia();
let mut depth = 1;
while depth > 0 {
if p.at(SyntaxKind::L_BRACE) {
depth += 1;
p.bump();
} else if p.at(SyntaxKind::R_BRACE) {
depth -= 1;
if depth > 0 {
p.bump();
}
} else if p.current_kind() == SyntaxKind::ERROR {
break; } else {
p.bump();
}
}
p.expect(SyntaxKind::R_BRACE);
}
pub fn is_name_kind(kind: SyntaxKind) -> bool {
if kind == SyntaxKind::IDENT {
return true;
}
!matches!(
kind,
SyntaxKind::ERROR
| SyntaxKind::WHITESPACE
| SyntaxKind::LINE_COMMENT
| SyntaxKind::BLOCK_COMMENT
| SyntaxKind::L_BRACE
| SyntaxKind::R_BRACE
| SyntaxKind::L_BRACKET
| SyntaxKind::R_BRACKET
| SyntaxKind::L_PAREN
| SyntaxKind::R_PAREN
| SyntaxKind::SEMICOLON
| SyntaxKind::COLON
| SyntaxKind::COLON_COLON
| SyntaxKind::COLON_GT
| SyntaxKind::COLON_GT_GT
| SyntaxKind::COLON_COLON_GT
| SyntaxKind::DOT
| SyntaxKind::DOT_DOT
| SyntaxKind::COMMA
| SyntaxKind::EQ
| SyntaxKind::EQ_EQ
| SyntaxKind::EQ_EQ_EQ
| SyntaxKind::BANG_EQ
| SyntaxKind::BANG_EQ_EQ
| SyntaxKind::LT
| SyntaxKind::GT
| SyntaxKind::LT_EQ
| SyntaxKind::GT_EQ
| SyntaxKind::AT
| SyntaxKind::AT_AT
| SyntaxKind::HASH
| SyntaxKind::STAR
| SyntaxKind::STAR_STAR
| SyntaxKind::PLUS
| SyntaxKind::MINUS
| SyntaxKind::SLASH
| SyntaxKind::PERCENT
| SyntaxKind::CARET
| SyntaxKind::AMP
| SyntaxKind::AMP_AMP
| SyntaxKind::PIPE
| SyntaxKind::PIPE_PIPE
| SyntaxKind::BANG
| SyntaxKind::TILDE
| SyntaxKind::QUESTION
| SyntaxKind::QUESTION_QUESTION
| SyntaxKind::ARROW
| SyntaxKind::FAT_ARROW
| SyntaxKind::INTEGER
| SyntaxKind::DECIMAL
| SyntaxKind::STRING
)
}
pub fn parse_identification<P: KerMLParser>(p: &mut P) {
p.skip_trivia();
p.start_node(SyntaxKind::NAME);
if p.at(SyntaxKind::LT) {
p.start_node(SyntaxKind::SHORT_NAME);
bump_and_skip(p); if p.at_name_token() || p.current_kind().is_keyword() {
p.bump();
}
p.skip_trivia();
p.expect(SyntaxKind::GT);
p.finish_node();
p.skip_trivia();
}
if p.at_name_token() {
p.bump();
}
p.finish_node();
}
fn should_stop_before_wildcard<P: KerMLParser>(p: &P) -> bool {
if p.at(SyntaxKind::COLON_COLON) {
let peek = p.peek_kind(1);
peek == SyntaxKind::STAR || peek == SyntaxKind::STAR_STAR
} else {
false
}
}
fn should_consume_dot<P: KerMLParser>(p: &P) -> bool {
if p.at(SyntaxKind::DOT) {
is_name_kind(p.peek_kind(1))
} else {
true
}
}
pub fn parse_qualified_name<P: KerMLParser>(p: &mut P, _tokens: &[(SyntaxKind, usize)]) {
p.start_node(SyntaxKind::QUALIFIED_NAME);
if p.at(SyntaxKind::DOLLAR) {
bump_and_skip(p);
consume_if(p, SyntaxKind::COLON_COLON);
}
if p.at(SyntaxKind::THIS_KW) {
p.bump();
p.finish_node();
return;
}
if p.at_name_token() {
p.bump();
}
while p.at_any(&[SyntaxKind::COLON_COLON, SyntaxKind::DOT]) {
if should_stop_before_wildcard(p) || !should_consume_dot(p) {
break;
}
bump_and_skip(p); if p.at_name_token() {
p.bump();
} else {
break;
}
}
p.finish_node();
}
fn looks_like_expression<P: KerMLParser>(p: &P) -> bool {
if p.at(SyntaxKind::IDENT) {
let peek1 = p.peek_kind(1);
matches!(
peek1,
SyntaxKind::GT | SyntaxKind::LT | SyntaxKind::PLUS | SyntaxKind::MINUS |
SyntaxKind::STAR | SyntaxKind::SLASH | SyntaxKind::PERCENT |
SyntaxKind::EQ_EQ | SyntaxKind::BANG_EQ | SyntaxKind::LT_EQ | SyntaxKind::GT_EQ |
SyntaxKind::EQ_EQ_EQ | SyntaxKind::BANG_EQ_EQ |
SyntaxKind::AMP_AMP | SyntaxKind::PIPE_PIPE | SyntaxKind::CARET |
SyntaxKind::DOT | SyntaxKind::ARROW | SyntaxKind::R_BRACE )
} else {
false
}
}
fn recover_body_element<P: KerMLParser>(p: &mut P) {
let expr_start = p.get_pos();
super::kerml_expressions::parse_expression(p);
if p.get_pos() > expr_start {
p.skip_trivia();
} else {
let got = if let Some(text) = p.current_token_text() {
format!("'{}'", text)
} else {
kind_to_name(p.current_kind()).to_string()
};
p.error(format!("unexpected {} in body", got));
p.bump();
}
}
pub fn parse_body<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::NAMESPACE_BODY);
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
} else if p.at(SyntaxKind::L_BRACE) {
bump_and_skip(p);
while !p.at(SyntaxKind::ERROR) && !p.at(SyntaxKind::R_BRACE) {
let start_pos = p.get_pos();
if looks_like_expression(p) {
super::kerml_expressions::parse_expression(p);
} else {
parse_namespace_element(p);
}
p.skip_trivia();
if p.get_pos() == start_pos && !p.at(SyntaxKind::ERROR) && !p.at(SyntaxKind::R_BRACE) {
recover_body_element(p);
}
}
p.expect(SyntaxKind::R_BRACE);
} else {
let found = if let Some(text) = p.current_token_text() {
format!("'{}' ({})", text, kind_to_name(p.current_kind()))
} else {
"end of file".to_string()
};
p.error(format!(
"expected ';' to end declaration or '{{' to start body, found {}",
found
))
}
p.finish_node();
}
pub fn parse_typing<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::TYPING);
if p.at(SyntaxKind::TYPED_KW) {
bump_and_skip(p);
p.expect(SyntaxKind::BY_KW);
} else if p.at(SyntaxKind::OF_KW) {
p.bump();
} else {
p.expect(SyntaxKind::COLON);
}
p.skip_trivia();
consume_if(p, SyntaxKind::TILDE);
parse_type_with_modifiers(p);
while p.at(SyntaxKind::COMMA) {
bump_and_skip(p);
parse_type_with_modifiers(p);
}
p.finish_node();
}
fn parse_type_with_modifiers<P: KerMLParser>(p: &mut P) {
parse_qualified_name_and_skip(p);
parse_optional_multiplicity(p);
while p.at(SyntaxKind::ORDERED_KW) || p.at(SyntaxKind::NONUNIQUE_KW) {
bump_and_skip(p);
}
}
fn parse_multiplicity_bound<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::STAR) {
p.bump();
} else if p.at(SyntaxKind::INTEGER) {
super::kerml_expressions::parse_expression(p);
} else if p.at_name_token() || p.at(SyntaxKind::L_PAREN) {
super::kerml_expressions::parse_expression(p);
}
}
fn parse_multiplicity_modifiers<P: KerMLParser>(p: &mut P) {
while p.at(SyntaxKind::ORDERED_KW) || p.at(SyntaxKind::NONUNIQUE_KW) {
bump_and_skip(p);
}
}
pub fn parse_multiplicity<P: KerMLParser>(p: &mut P) {
if !p.at(SyntaxKind::L_BRACKET) {
return;
}
p.start_node(SyntaxKind::MULTIPLICITY);
bump_and_skip(p);
if !p.at(SyntaxKind::R_BRACKET) {
let is_modifier = p.at(SyntaxKind::ORDERED_KW) || p.at(SyntaxKind::NONUNIQUE_KW);
if !is_modifier {
parse_multiplicity_bound(p);
p.skip_trivia();
if p.at(SyntaxKind::DOT_DOT) {
bump_and_skip(p);
parse_multiplicity_bound(p);
}
p.skip_trivia();
}
parse_multiplicity_modifiers(p);
}
p.skip_trivia();
p.expect(SyntaxKind::R_BRACKET);
p.finish_node();
}
pub fn parse_multiplicity_definition<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::USAGE);
expect_and_skip(p, SyntaxKind::MULTIPLICITY_KW);
parse_optional_identification(p);
parse_optional_multiplicity(p);
p.parse_body();
p.finish_node();
}
fn parse_single_specialization<P: KerMLParser>(p: &mut P, keyword: SyntaxKind) {
p.start_node(SyntaxKind::SPECIALIZATION);
bump_and_skip(p);
if (keyword == SyntaxKind::DISJOINT_KW && p.at(SyntaxKind::FROM_KW))
|| (keyword == SyntaxKind::INVERSE_KW && p.at(SyntaxKind::OF_KW))
{
bump_and_skip(p);
}
parse_optional_visibility(p);
parse_qualified_name_and_skip(p);
p.finish_node();
p.skip_trivia();
while p.at(SyntaxKind::COMMA) {
p.start_node(SyntaxKind::SPECIALIZATION);
bump_and_skip(p);
parse_optional_visibility(p);
parse_qualified_name_and_skip(p);
p.finish_node();
p.skip_trivia();
}
}
pub fn parse_specializations<P: KerMLParser>(p: &mut P) {
while p.at_any(&[
SyntaxKind::COLON,
SyntaxKind::TYPED_KW,
SyntaxKind::OF_KW,
SyntaxKind::COLON_GT,
SyntaxKind::COLON_GT_GT,
SyntaxKind::COLON_COLON_GT,
SyntaxKind::SPECIALIZES_KW,
SyntaxKind::SUBSETS_KW,
SyntaxKind::REDEFINES_KW,
SyntaxKind::REFERENCES_KW,
SyntaxKind::CONJUGATES_KW,
SyntaxKind::TILDE,
SyntaxKind::DISJOINT_KW,
SyntaxKind::INTERSECTS_KW,
SyntaxKind::DIFFERENCES_KW,
SyntaxKind::UNIONS_KW,
SyntaxKind::CHAINS_KW,
SyntaxKind::INVERSE_KW,
SyntaxKind::FEATURING_KW,
SyntaxKind::CROSSES_KW,
SyntaxKind::FAT_ARROW,
]) {
if p.at(SyntaxKind::COLON) || p.at(SyntaxKind::TYPED_KW) || p.at(SyntaxKind::OF_KW) {
parse_typing(p);
p.skip_trivia();
continue;
}
let keyword = p.current_kind();
parse_single_specialization(p, keyword);
}
}
pub fn parse_package<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::PACKAGE);
if p.at(SyntaxKind::PACKAGE_KW) || p.at(SyntaxKind::NAMESPACE_KW) {
p.bump();
} else {
p.expect(SyntaxKind::PACKAGE_KW);
}
p.skip_trivia();
parse_optional_identification(p);
p.skip_trivia();
p.parse_body();
p.finish_node();
}
pub fn parse_library_package<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::LIBRARY_PACKAGE);
consume_if(p, SyntaxKind::STANDARD_KW);
expect_and_skip(p, SyntaxKind::LIBRARY_KW);
expect_and_skip(p, SyntaxKind::PACKAGE_KW);
parse_optional_identification(p);
p.skip_trivia();
p.parse_body();
p.finish_node();
}
pub fn parse_import<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::IMPORT);
expect_and_skip(p, SyntaxKind::IMPORT_KW);
consume_if(p, SyntaxKind::ALL_KW);
parse_qualified_name_and_skip(p);
parse_import_wildcards(p);
p.skip_trivia();
if p.at(SyntaxKind::L_BRACKET) {
parse_filter_package(p);
}
p.skip_trivia();
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
} else if p.at(SyntaxKind::L_BRACE) {
p.parse_body();
} else {
error_missing_body_terminator(p, "import statement");
}
p.finish_node();
}
fn parse_import_wildcards<P: KerMLParser>(p: &mut P) {
while p.at(SyntaxKind::COLON_COLON) {
bump_and_skip(p);
if p.at(SyntaxKind::STAR_STAR) {
bump_and_skip(p);
} else if p.at(SyntaxKind::STAR) {
bump_and_skip(p);
consume_if(p, SyntaxKind::STAR);
} else {
break;
}
}
}
fn parse_filter_package<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::FILTER_PACKAGE);
while p.at(SyntaxKind::L_BRACKET) {
bump_and_skip(p);
if p.at(SyntaxKind::AT) || p.at(SyntaxKind::AT_AT) {
bump_and_skip(p); parse_qualified_name_and_skip(p);
} else {
super::kerml_expressions::parse_expression(p);
}
p.skip_trivia();
expect_and_skip(p, SyntaxKind::R_BRACKET);
}
p.finish_node(); }
pub fn parse_alias<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::ALIAS_MEMBER);
expect_and_skip(p, SyntaxKind::ALIAS_KW);
parse_identification_and_skip(p);
expect_and_skip(p, SyntaxKind::FOR_KW);
parse_qualified_name_and_skip(p);
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
} else if p.at(SyntaxKind::L_BRACE) {
p.parse_body();
} else {
error_missing_body_terminator(p, "alias declaration");
}
p.finish_node();
}
pub fn parse_definition_impl<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::DEFINITION);
while p.at(SyntaxKind::ABSTRACT_KW) || p.at(SyntaxKind::VARIATION_KW) {
bump_and_skip(p);
}
let is_predicate = p.at(SyntaxKind::PREDICATE_KW);
let is_function = p.at(SyntaxKind::FUNCTION_KW);
if p.at_any(&[
SyntaxKind::CLASS_KW,
SyntaxKind::STRUCT_KW,
SyntaxKind::DATATYPE_KW,
SyntaxKind::BEHAVIOR_KW,
SyntaxKind::FUNCTION_KW,
SyntaxKind::CLASSIFIER_KW,
SyntaxKind::INTERACTION_KW,
SyntaxKind::PREDICATE_KW,
SyntaxKind::METACLASS_KW,
SyntaxKind::TYPE_KW,
]) {
p.bump();
} else if p.at(SyntaxKind::ASSOC_KW) {
bump_and_skip(p);
consume_if(p, SyntaxKind::STRUCT_KW);
}
p.skip_trivia();
consume_if(p, SyntaxKind::ALL_KW);
parse_optional_identification(p);
parse_optional_multiplicity(p);
parse_specializations(p);
p.skip_trivia();
while p.at(SyntaxKind::ORDERED_KW) || p.at(SyntaxKind::NONUNIQUE_KW) {
bump_and_skip(p);
}
parse_optional_multiplicity(p);
parse_specializations(p);
p.skip_trivia();
while p.at(SyntaxKind::ORDERED_KW) || p.at(SyntaxKind::NONUNIQUE_KW) {
bump_and_skip(p);
}
if is_predicate || is_function {
parse_calc_body(p);
} else {
p.parse_body();
}
p.finish_node();
}
fn parse_calc_body_element<P: KerMLParser>(p: &mut P) -> bool {
if p.at_any(&[
SyntaxKind::IN_KW,
SyntaxKind::OUT_KW,
SyntaxKind::INOUT_KW,
SyntaxKind::RETURN_KW,
]) {
parse_parameter_impl(p);
true
} else if p.at_any(&[
SyntaxKind::ATTRIBUTE_KW,
SyntaxKind::PART_KW,
SyntaxKind::ITEM_KW,
SyntaxKind::CALC_KW,
SyntaxKind::CONSTRAINT_KW,
SyntaxKind::DOC_KW,
SyntaxKind::COMMENT_KW,
SyntaxKind::PRIVATE_KW,
SyntaxKind::PUBLIC_KW,
SyntaxKind::PROTECTED_KW,
SyntaxKind::FEATURE_KW,
SyntaxKind::STEP_KW,
SyntaxKind::EXPR_KW,
SyntaxKind::FUNCTION_KW,
]) {
parse_namespace_element(p);
true
} else if p.at_name_token()
|| p.at(SyntaxKind::L_PAREN)
|| p.at(SyntaxKind::INTEGER)
|| p.at(SyntaxKind::STRING)
{
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
}
true
} else {
parse_namespace_element(p);
true
}
}
pub fn parse_calc_body<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::NAMESPACE_BODY);
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
} else if p.at(SyntaxKind::L_BRACE) {
bump_and_skip(p);
while !p.at(SyntaxKind::R_BRACE) && !p.at(SyntaxKind::ERROR) {
let start_pos = p.get_pos();
parse_calc_body_element(p);
p.skip_trivia();
if p.get_pos() == start_pos && !p.at(SyntaxKind::R_BRACE) {
let got = if let Some(text) = p.current_token_text() {
format!("'{}'", text)
} else {
kind_to_name(p.current_kind()).to_string()
};
p.error(format!("unexpected {} in calc body", got));
p.bump();
}
}
p.expect(SyntaxKind::R_BRACE);
} else {
error_missing_body_terminator(p, "calc/function definition");
}
p.finish_node();
}
fn parse_feature_prefix_modifiers<P: KerMLParser>(p: &mut P) {
while p.at_any(&[
SyntaxKind::VAR_KW,
SyntaxKind::COMPOSITE_KW,
SyntaxKind::PORTION_KW,
SyntaxKind::MEMBER_KW,
SyntaxKind::ABSTRACT_KW,
SyntaxKind::DERIVED_KW,
SyntaxKind::CONST_KW,
SyntaxKind::END_KW,
SyntaxKind::VARIATION_KW,
SyntaxKind::READONLY_KW,
SyntaxKind::REF_KW,
]) {
p.bump();
p.skip_trivia();
}
while p.at(SyntaxKind::HASH) {
parse_prefix_metadata(p);
p.skip_trivia();
}
}
fn parse_optional_feature_keyword<P: KerMLParser>(p: &mut P) -> bool {
if p.at(SyntaxKind::INV_KW) {
p.bump();
p.skip_trivia();
if p.at(SyntaxKind::NOT_KW) {
p.bump();
p.skip_trivia();
}
true
} else if p.at_any(&[
SyntaxKind::FEATURE_KW,
SyntaxKind::STEP_KW,
SyntaxKind::EXPR_KW,
]) {
p.bump();
true
} else if p.at(SyntaxKind::IDENT) {
if let Some(text) = p.current_token_text() {
if text == "feature" || text == "step" || text == "expr" {
p.bump();
true
} else {
false
}
} else {
false
}
} else {
false
}
}
fn parse_usage_name_or_shorthand<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::REDEFINES_KW)
|| p.at(SyntaxKind::COLON_GT_GT)
|| p.at(SyntaxKind::SUBSETS_KW)
|| p.at(SyntaxKind::COLON_GT)
{
p.start_node(SyntaxKind::SPECIALIZATION);
bump_and_skip(p);
parse_optional_qualified_name(p);
p.finish_node();
while p.at(SyntaxKind::COMMA) {
bump_and_skip(p);
p.start_node(SyntaxKind::SPECIALIZATION);
parse_qualified_name_and_skip(p);
p.finish_node();
}
} else if p.at_name_token() || p.at(SyntaxKind::LT) {
if p.at(SyntaxKind::IDENT) {
let peek1 = p.peek_kind(1);
if peek1 == SyntaxKind::IDENT || peek1 == SyntaxKind::LT {
p.start_node(SyntaxKind::TYPING);
p.bump(); p.skip_trivia();
p.finish_node();
p.parse_identification();
return;
}
}
p.parse_identification();
}
}
fn parse_usage_details<P: KerMLParser>(p: &mut P) {
p.skip_trivia();
parse_optional_multiplicity(p);
parse_optional_typing(p);
parse_optional_multiplicity(p);
parse_ordering_modifiers(p);
parse_specializations(p);
p.skip_trivia();
parse_optional_multiplicity(p);
parse_ordering_modifiers(p);
parse_feature_relationships(p);
p.skip_trivia();
}
fn parse_ordering_modifiers<P: KerMLParser>(p: &mut P) {
while p.at(SyntaxKind::ORDERED_KW) || p.at(SyntaxKind::NONUNIQUE_KW) {
bump_and_skip(p);
}
}
fn parse_optional_default_value<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::EQ) || p.at(SyntaxKind::COLON_EQ) || p.at(SyntaxKind::DEFAULT_KW) {
bump_and_skip(p);
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
}
}
pub fn parse_usage_impl<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::USAGE);
parse_feature_prefix_modifiers(p);
let _consumed_feature_keyword = parse_optional_feature_keyword(p);
p.skip_trivia();
if p.at(SyntaxKind::ALL_KW) {
p.bump();
p.skip_trivia();
}
parse_usage_name_or_shorthand(p);
parse_usage_details(p);
parse_optional_default_value(p);
p.parse_body();
p.finish_node();
}
pub fn parse_invariant<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::USAGE);
p.expect(SyntaxKind::INV_KW);
p.skip_trivia();
if p.at(SyntaxKind::NOT_KW) {
p.bump();
p.skip_trivia();
}
if p.at_name_token() || p.at(SyntaxKind::LT) {
p.parse_identification();
p.skip_trivia();
}
if p.at(SyntaxKind::L_BRACE) {
p.start_node(SyntaxKind::NAMESPACE_BODY);
p.bump(); p.skip_trivia();
if p.at(SyntaxKind::DOC_KW) || p.at(SyntaxKind::COMMENT_KW) {
parse_annotation(p);
p.skip_trivia();
}
if !p.at(SyntaxKind::R_BRACE) {
super::kerml_expressions::parse_expression(p);
}
p.skip_trivia();
p.expect(SyntaxKind::R_BRACE);
p.finish_node();
} else {
p.parse_body();
}
p.finish_node();
}
pub fn parse_parameter_impl<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::USAGE);
if p.at_any(&[
SyntaxKind::IN_KW,
SyntaxKind::OUT_KW,
SyntaxKind::INOUT_KW,
SyntaxKind::END_KW,
SyntaxKind::RETURN_KW,
]) {
p.bump();
}
p.skip_trivia();
parse_feature_prefix_modifiers(p);
if p.at_any(&[
SyntaxKind::ATTRIBUTE_KW,
SyntaxKind::PART_KW,
SyntaxKind::ITEM_KW,
SyntaxKind::CALC_KW,
SyntaxKind::ACTION_KW,
SyntaxKind::STATE_KW,
SyntaxKind::PORT_KW,
SyntaxKind::FEATURE_KW,
SyntaxKind::STEP_KW,
SyntaxKind::EXPR_KW,
]) {
bump_and_skip(p);
}
if p.at(SyntaxKind::IDENT) {
let peek1 = p.peek_kind(1);
if peek1 == SyntaxKind::IDENT {
p.bump();
p.skip_trivia();
if p.at_name_token() {
p.parse_identification();
}
} else {
parse_usage_name_or_shorthand(p);
}
} else {
parse_usage_name_or_shorthand(p);
}
parse_usage_details(p);
parse_optional_default_value(p);
p.parse_body();
p.finish_node();
}
fn parse_multiplicity_with_ordering<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
while p.at(SyntaxKind::ORDERED_KW) || p.at(SyntaxKind::NONUNIQUE_KW) {
bump_and_skip(p);
}
}
}
fn parse_prefix_modifiers<P: KerMLParser>(p: &mut P) {
while p.at_any(&[
SyntaxKind::REF_KW,
SyntaxKind::READONLY_KW,
SyntaxKind::DERIVED_KW,
SyntaxKind::ABSTRACT_KW,
SyntaxKind::VARIATION_KW,
SyntaxKind::VAR_KW,
SyntaxKind::COMPOSITE_KW,
SyntaxKind::PORTION_KW,
SyntaxKind::INDIVIDUAL_KW,
]) {
bump_and_skip(p);
}
}
fn parse_optional_sysml_usage_keyword<P: KerMLParser>(p: &mut P) {
if p.at_any(&[
SyntaxKind::ITEM_KW,
SyntaxKind::PART_KW,
SyntaxKind::ACTION_KW,
SyntaxKind::STATE_KW,
SyntaxKind::ATTRIBUTE_KW,
SyntaxKind::PORT_KW,
]) {
bump_and_skip(p);
}
}
fn parse_end_feature_prefix<P: KerMLParser>(p: &mut P) {
while p.at(SyntaxKind::HASH) {
parse_prefix_metadata(p);
p.skip_trivia();
}
parse_prefix_modifiers(p);
parse_multiplicity_with_ordering(p);
parse_optional_sysml_usage_keyword(p);
}
fn parse_feature_details<P: KerMLParser>(p: &mut P, parse_id: bool) {
if parse_id {
parse_optional_identification(p);
}
parse_multiplicity_with_ordering(p);
parse_optional_typing(p);
parse_specializations(p);
p.skip_trivia();
parse_feature_relationships(p);
p.skip_trivia();
}
fn parse_end_feature_with_keyword<P: KerMLParser>(p: &mut P) {
bump_and_skip(p);
if p.at(SyntaxKind::REDEFINES_KW)
|| p.at(SyntaxKind::COLON_GT_GT)
|| p.at(SyntaxKind::SUBSETS_KW)
|| p.at(SyntaxKind::COLON_GT)
|| p.at(SyntaxKind::REFERENCES_KW)
|| p.at(SyntaxKind::COLON_COLON_GT)
{
parse_feature_details(p, false);
} else {
parse_feature_details(p, true);
}
}
fn parse_typing_and_relationships<P: KerMLParser>(p: &mut P) {
parse_optional_typing(p);
parse_specializations(p);
p.skip_trivia();
parse_feature_relationships(p);
p.skip_trivia();
}
fn parse_end_feature_with_name<P: KerMLParser>(p: &mut P) {
parse_identification_and_skip(p);
parse_multiplicity_with_ordering(p);
parse_specializations(p);
p.skip_trivia();
parse_feature_relationships(p);
p.skip_trivia();
if p.at(SyntaxKind::FEATURE_KW) {
bump_and_skip(p);
parse_feature_details(p, true);
} else {
parse_typing_and_relationships(p);
}
}
fn parse_end_feature_minimal<P: KerMLParser>(p: &mut P) {
parse_multiplicity_with_ordering(p);
parse_specializations(p);
p.skip_trivia();
if p.at(SyntaxKind::FEATURE_KW) {
bump_and_skip(p);
parse_feature_details(p, true);
}
}
pub fn parse_end_feature_or_parameter<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::USAGE);
consume_if(p, SyntaxKind::CONST_KW);
expect_and_skip(p, SyntaxKind::END_KW);
parse_end_feature_prefix(p);
if p.at(SyntaxKind::FEATURE_KW) {
parse_end_feature_with_keyword(p);
} else if p.at_name_token() || p.at(SyntaxKind::LT) {
if p.at(SyntaxKind::IDENT) {
let peek1 = p.peek_kind(1);
if peek1 == SyntaxKind::IDENT || peek1 == SyntaxKind::LT {
p.start_node(SyntaxKind::TYPING);
p.bump(); p.skip_trivia();
p.finish_node();
p.parse_identification();
parse_multiplicity_with_ordering(p);
parse_specializations(p);
p.skip_trivia();
parse_feature_relationships(p);
p.skip_trivia();
} else {
parse_end_feature_with_name(p);
}
} else {
parse_end_feature_with_name(p);
}
} else {
parse_end_feature_minimal(p);
}
parse_optional_default_value(p);
p.parse_body();
p.finish_node();
}
fn parse_connector_name_or_specialization<P: KerMLParser>(
p: &mut P,
looks_like_direct_endpoint: bool,
) {
if p.at(SyntaxKind::COLON_GT)
|| p.at(SyntaxKind::COLON_GT_GT)
|| p.at(SyntaxKind::SUBSETS_KW)
|| p.at(SyntaxKind::SPECIALIZES_KW)
|| p.at(SyntaxKind::REDEFINES_KW)
{
parse_specializations(p);
p.skip_trivia();
} else if p.at(SyntaxKind::EQ) {
bump_and_skip(p);
parse_optional_qualified_name(p);
} else if !looks_like_direct_endpoint && (p.at_name_token() || p.at(SyntaxKind::LT)) {
parse_identification_and_skip(p);
if p.at(SyntaxKind::EQ) {
bump_and_skip(p);
parse_optional_qualified_name(p);
} else {
parse_specializations(p);
p.skip_trivia();
}
}
}
fn parse_nary_connector_endpoints<P: KerMLParser>(p: &mut P) -> bool {
if !p.at(SyntaxKind::L_PAREN) {
return false;
}
p.bump(); p.skip_trivia();
if p.at_name_token() || p.at(SyntaxKind::L_BRACKET) {
parse_connection_end(p);
p.skip_trivia();
}
while p.at(SyntaxKind::COMMA) {
p.bump(); p.skip_trivia();
if p.at_name_token() || p.at(SyntaxKind::L_BRACKET) {
parse_connection_end(p);
p.skip_trivia();
}
}
if p.at(SyntaxKind::R_PAREN) {
p.bump(); p.skip_trivia();
}
true
}
fn parse_binary_connector_endpoints<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::FROM_KW) {
p.bump();
p.skip_trivia();
parse_connection_end(p);
p.skip_trivia();
} else if !p.at(SyntaxKind::TO_KW) && (p.at_name_token() || p.at(SyntaxKind::L_PAREN)) {
parse_connection_end(p);
p.skip_trivia();
}
if p.at(SyntaxKind::TO_KW) {
p.bump();
p.skip_trivia();
parse_connection_end(p);
p.skip_trivia();
}
}
pub fn parse_connector_usage<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::CONNECTOR);
while p.at_any(&[
SyntaxKind::VAR_KW,
SyntaxKind::COMPOSITE_KW,
SyntaxKind::PORTION_KW,
SyntaxKind::MEMBER_KW,
SyntaxKind::ABSTRACT_KW,
SyntaxKind::DERIVED_KW,
SyntaxKind::CONST_KW,
SyntaxKind::END_KW,
]) {
bump_and_skip(p);
}
if p.at_any(&[
SyntaxKind::BINDING_KW,
SyntaxKind::SUCCESSION_KW,
SyntaxKind::FIRST_KW,
]) {
parse_binding_or_succession_impl(p);
return;
}
expect_and_skip(p, SyntaxKind::CONNECTOR_KW);
consume_if(p, SyntaxKind::ALL_KW);
if p.at(SyntaxKind::FEATURED_KW) {
parse_feature_relationships(p);
p.skip_trivia();
parse_binary_connector_endpoints(p);
p.parse_body();
p.finish_node();
return;
}
let looks_like_direct =
looks_like_qualified_name_before(p, &[SyntaxKind::TO_KW, SyntaxKind::FROM_KW]);
parse_connector_name_or_specialization(p, looks_like_direct);
parse_optional_typing(p);
parse_optional_multiplicity(p);
parse_feature_relationships(p);
p.skip_trivia();
if parse_nary_connector_endpoints(p) {
p.parse_body();
p.finish_node();
return;
}
parse_binary_connector_endpoints(p);
p.parse_body();
p.finish_node();
}
fn parse_connection_end<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::CONNECTION_END);
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
if p.at_name_token() {
let _checkpoint_pos = p.get_pos();
p.parse_qualified_name();
p.skip_trivia();
if p.at(SyntaxKind::REFERENCES_KW) || p.at(SyntaxKind::COLON_COLON_GT) {
p.bump();
p.skip_trivia();
if p.at_name_token() {
p.parse_qualified_name();
}
}
}
p.finish_node();
}
fn parse_binding_succession_prefix<P: KerMLParser>(
p: &mut P,
looks_like_direct_endpoint: bool,
) -> bool {
let mut parsed_name = false;
if p.at(SyntaxKind::REDEFINES_KW) || p.at(SyntaxKind::COLON_GT_GT) {
p.start_node(SyntaxKind::SPECIALIZATION);
p.bump();
p.skip_trivia();
if p.at_name_token() {
p.parse_qualified_name();
p.skip_trivia();
parsed_name = true;
}
p.finish_node();
} else if !looks_like_direct_endpoint && (p.at_name_token() || p.at(SyntaxKind::LT)) {
p.parse_identification();
p.skip_trivia();
parsed_name = true;
}
parsed_name
}
fn parse_succession_modifiers<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::COLON) {
parse_typing(p);
p.skip_trivia();
}
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
}
fn parse_succession_first_pattern<P: KerMLParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
p.parse_qualified_name();
p.skip_trivia();
if p.at(SyntaxKind::THEN_KW) {
p.bump();
p.skip_trivia();
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
p.parse_qualified_name();
}
}
fn parse_endpoint_references<P: KerMLParser>(p: &mut P, parsed_name: bool) {
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
if !parsed_name && p.at_name_token() {
p.parse_qualified_name();
p.skip_trivia();
}
if p.at(SyntaxKind::EQ) || p.at(SyntaxKind::THEN_KW) {
p.bump();
p.skip_trivia();
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
if p.at_name_token() {
p.parse_qualified_name();
}
}
}
fn parse_binding_of_clause<P: KerMLParser>(p: &mut P) {
if p.at(SyntaxKind::OF_KW) {
p.bump();
p.skip_trivia();
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
if p.at_name_token() {
parse_feature_chain_or_qualified_name(p);
p.skip_trivia();
}
if p.at(SyntaxKind::EQ) {
p.bump();
p.skip_trivia();
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
if p.at_name_token() {
parse_feature_chain_or_qualified_name(p);
p.skip_trivia();
}
}
}
}
fn should_parse_first_pattern<P: KerMLParser>(p: &P, is_succession: bool) -> bool {
is_succession && p.at(SyntaxKind::FIRST_KW)
}
fn parse_binding_or_succession_impl<P: KerMLParser>(p: &mut P) {
let is_succession = p.at(SyntaxKind::SUCCESSION_KW) || p.at(SyntaxKind::FIRST_KW);
let is_shorthand_first = p.at(SyntaxKind::FIRST_KW);
if !is_shorthand_first {
bump_and_skip(p);
}
consume_if(p, SyntaxKind::ALL_KW);
let parsed_name = if should_parse_first_pattern(p, is_succession) {
false } else {
let looks_like_direct = if is_succession {
let next_after_name = p.peek_kind(1);
next_after_name == SyntaxKind::THEN_KW
} else {
looks_like_name_then(p, SyntaxKind::EQ)
};
parse_binding_succession_prefix(p, looks_like_direct)
};
if p.at(SyntaxKind::L_BRACKET) {
parse_multiplicity(p);
p.skip_trivia();
}
if !is_succession {
parse_binding_of_clause(p);
}
if is_succession {
parse_succession_modifiers(p);
}
parse_specializations(p);
p.skip_trivia();
if should_parse_first_pattern(p, is_succession) {
parse_succession_first_pattern(p);
} else {
parse_endpoint_references(p, parsed_name);
}
p.skip_trivia();
p.parse_body();
p.finish_node();
}
pub fn parse_flow_usage<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::USAGE);
consume_if(p, SyntaxKind::ABSTRACT_KW);
consume_if(p, SyntaxKind::SUCCESSION_KW);
expect_and_skip(p, SyntaxKind::FLOW_KW);
let starts_with_all = consume_if(p, SyntaxKind::ALL_KW);
let looks_like_direct = starts_with_all || {
if p.at_name_token() {
let next = p.peek_kind(1);
matches!(next, SyntaxKind::DOT | SyntaxKind::TO_KW)
} else {
false
}
};
if looks_like_direct {
parse_flow_direct_pattern(p);
} else {
parse_flow_declaration_pattern(p);
}
p.skip_trivia();
parse_body(p);
p.finish_node();
}
fn parse_flow_direct_pattern<P: KerMLParser>(p: &mut P) {
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::TO_KW) {
bump_and_skip(p);
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
}
}
fn parse_flow_declaration_pattern<P: KerMLParser>(p: &mut P) {
parse_optional_identification(p);
parse_optional_multiplicity(p);
parse_optional_typing(p);
parse_specializations(p);
p.skip_trivia();
if p.at(SyntaxKind::OF_KW) {
bump_and_skip(p);
parse_qualified_name_and_skip(p);
}
if p.at(SyntaxKind::FROM_KW) {
bump_and_skip(p);
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
}
if p.at(SyntaxKind::TO_KW) {
bump_and_skip(p);
super::kerml_expressions::parse_expression(p);
p.skip_trivia();
}
}
fn parse_featured_by<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::RELATIONSHIP);
bump_and_skip(p);
if p.at(SyntaxKind::BY_KW) {
bump_and_skip(p);
parse_optional_qualified_name(p);
}
p.finish_node();
}
fn parse_inverse_of<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::RELATIONSHIP);
bump_and_skip(p);
if p.at(SyntaxKind::OF_KW) {
bump_and_skip(p);
parse_optional_qualified_name(p);
}
p.finish_node();
}
fn parse_simple_relationship<P: KerMLParser>(p: &mut P) {
p.start_node(SyntaxKind::RELATIONSHIP);
bump_and_skip(p);
parse_optional_qualified_name(p);
p.finish_node();
}
pub fn parse_feature_relationships<P: KerMLParser>(p: &mut P) {
while p.at_any(&[
SyntaxKind::FEATURED_KW,
SyntaxKind::INVERSE_KW,
SyntaxKind::CHAINS_KW,
SyntaxKind::CROSSES_KW,
SyntaxKind::FAT_ARROW,
]) {
p.skip_trivia();
match p.current_kind() {
SyntaxKind::FEATURED_KW => parse_featured_by(p),
SyntaxKind::INVERSE_KW => parse_inverse_of(p),
SyntaxKind::CHAINS_KW | SyntaxKind::CROSSES_KW | SyntaxKind::FAT_ARROW => {
parse_simple_relationship(p);
}
_ => break,
}
}
}