use super::*;
pub fn parse_sysml_file<P: SysMLParser>(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_package_body_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 {
p.current_kind().display_name().to_string()
};
p.error(format!("unexpected {} in top level", got));
p.bump();
}
}
p.finish_node();
}
pub fn parse_package_body_element<P: SysMLParser>(p: &mut P) {
p.skip_trivia();
if p.at_any(&[
SyntaxKind::PUBLIC_KW,
SyntaxKind::PRIVATE_KW,
SyntaxKind::PROTECTED_KW,
]) {
bump_keyword(p);
}
while p.at(SyntaxKind::HASH) {
parse_prefix_metadata(p);
p.skip_trivia();
}
match p.current_kind() {
SyntaxKind::PACKAGE_KW => parse_package(p),
SyntaxKind::LIBRARY_KW | SyntaxKind::STANDARD_KW => parse_library_package(p),
SyntaxKind::IMPORT_KW => parse_import(p),
SyntaxKind::ALIAS_KW => parse_alias(p),
SyntaxKind::DEPENDENCY_KW => p.parse_dependency(),
SyntaxKind::COMMENT_KW | SyntaxKind::DOC_KW | SyntaxKind::LOCALE_KW => {
parse_annotation(p);
}
SyntaxKind::FILTER_KW => p.parse_filter(),
SyntaxKind::AT => p.parse_metadata_usage(),
SyntaxKind::ABSTRACT_KW
| SyntaxKind::VARIATION_KW
| SyntaxKind::DERIVED_KW
| SyntaxKind::READONLY_KW
| SyntaxKind::CONSTANT_KW
| SyntaxKind::VAR_KW
| SyntaxKind::COMPOSITE_KW
| SyntaxKind::PORTION_KW
| SyntaxKind::IN_KW
| SyntaxKind::OUT_KW
| SyntaxKind::INOUT_KW
| SyntaxKind::END_KW
| SyntaxKind::INDIVIDUAL_KW => {
p.parse_definition_or_usage();
}
SyntaxKind::ACTION_KW => {
let (_, after_name) = peek_past_optional_name(p, 1);
if after_name == SyntaxKind::SEND_KW {
bump_keyword(p); p.parse_identification(); p.skip_trivia();
parse_send_action(p);
return;
} else if after_name == SyntaxKind::ACCEPT_KW {
bump_keyword(p); p.parse_identification(); p.skip_trivia();
parse_accept_action(p);
return;
} else if after_name == SyntaxKind::PERFORM_KW {
bump_keyword(p); p.parse_identification(); p.skip_trivia();
parse_perform_action(p);
return;
}
p.parse_definition_or_usage();
}
SyntaxKind::DEF_KW => {
p.parse_definition_or_usage();
}
SyntaxKind::PART_KW
| SyntaxKind::ATTRIBUTE_KW
| SyntaxKind::PORT_KW
| SyntaxKind::ITEM_KW
| SyntaxKind::STATE_KW
| SyntaxKind::OCCURRENCE_KW
| SyntaxKind::CONSTRAINT_KW
| SyntaxKind::REQUIREMENT_KW
| SyntaxKind::CASE_KW
| SyntaxKind::CALC_KW
| SyntaxKind::CONNECTION_KW
| SyntaxKind::INTERFACE_KW
| SyntaxKind::ALLOCATION_KW
| SyntaxKind::VIEW_KW
| SyntaxKind::VIEWPOINT_KW
| SyntaxKind::RENDERING_KW
| SyntaxKind::METADATA_KW
| SyntaxKind::ENUM_KW
| SyntaxKind::ANALYSIS_KW
| SyntaxKind::VERIFICATION_KW
| SyntaxKind::USE_KW
| SyntaxKind::CONCERN_KW
| SyntaxKind::PARALLEL_KW
| SyntaxKind::EVENT_KW
| SyntaxKind::MESSAGE_KW
| SyntaxKind::SNAPSHOT_KW
| SyntaxKind::TIMESLICE_KW
| SyntaxKind::ABOUT_KW => {
p.parse_definition_or_usage();
}
SyntaxKind::FRAME_KW => parse_frame_usage(p),
SyntaxKind::RENDER_KW => parse_render_usage(p),
SyntaxKind::REF_KW => {
let lookahead = skip_trivia_lookahead(p, 1);
if matches!(
p.peek_kind(lookahead),
SyntaxKind::COLON_GT_GT | SyntaxKind::COLON_GT
) {
p.parse_redefines_feature_member();
} else {
p.parse_definition_or_usage();
}
}
SyntaxKind::ALLOCATE_KW => {
parse_allocate_usage(p);
}
SyntaxKind::TERMINATE_KW => {
parse_terminate_action(p);
}
SyntaxKind::FLOW_KW => {
let lookahead = skip_trivia_lookahead(p, 1);
if p.peek_kind(lookahead) == SyntaxKind::DEF_KW {
p.parse_definition_or_usage();
} else {
parse_flow_usage(p);
}
}
SyntaxKind::RETURN_KW => {
let lookahead = skip_trivia_lookahead(p, 1);
let after_return = p.peek_kind(lookahead);
if after_return == SyntaxKind::COLON || after_return == SyntaxKind::TYPED_KW {
parse_sysml_parameter(p);
} else if after_return == SyntaxKind::IDENT {
let after_that = p.peek_kind(skip_trivia_lookahead(p, lookahead + 1));
if after_that == SyntaxKind::COLON
|| after_that == SyntaxKind::TYPED_KW
|| after_that == SyntaxKind::L_BRACKET
|| after_that == SyntaxKind::COLON_GT
|| after_that == SyntaxKind::COLON_GT_GT
|| after_that == SyntaxKind::SEMICOLON
|| after_that == SyntaxKind::EQ
{
parse_sysml_parameter(p);
} else {
parse_return_expression(p);
}
} else if is_usage_keyword(after_return) {
parse_sysml_parameter(p);
} else {
parse_return_expression(p);
}
}
SyntaxKind::CONST_KW => {
parse_sysml_parameter(p);
}
SyntaxKind::CONNECTOR_KW => parse_connector_usage(p),
SyntaxKind::PERFORM_KW => parse_perform_action(p),
SyntaxKind::ACCEPT_KW => parse_accept_action(p),
SyntaxKind::SEND_KW => parse_send_action(p),
SyntaxKind::IF_KW => parse_if_action(p),
SyntaxKind::WHILE_KW | SyntaxKind::LOOP_KW => parse_loop_action(p),
SyntaxKind::FOR_KW => parse_for_loop(p),
SyntaxKind::FIRST_KW => parse_first_action(p),
SyntaxKind::THEN_KW => parse_then_succession(p),
SyntaxKind::ELSE_KW => parse_else_succession(p),
SyntaxKind::FORK_KW
| SyntaxKind::JOIN_KW
| SyntaxKind::MERGE_KW
| SyntaxKind::DECIDE_KW => {
parse_control_node(p);
}
SyntaxKind::ENTRY_KW | SyntaxKind::EXIT_KW | SyntaxKind::DO_KW => {
parse_state_subaction(p);
}
SyntaxKind::TRANSITION_KW => parse_transition(p),
SyntaxKind::SUBJECT_KW => {
let lookahead = skip_trivia_lookahead(p, 1);
if p.peek_kind(lookahead) == SyntaxKind::EQ
|| p.peek_kind(lookahead) == SyntaxKind::COLON_GT_GT
{
p.parse_shorthand_feature_member();
} else {
parse_subject_usage(p);
}
}
SyntaxKind::ACTOR_KW => {
let (_, next) = peek_past_optional_name(p, 1);
if next == SyntaxKind::EQ
|| next == SyntaxKind::COLON_GT_GT
|| next == SyntaxKind::COLON_GT
{
p.parse_shorthand_feature_member();
} else {
parse_actor_usage(p);
}
}
SyntaxKind::STAKEHOLDER_KW => {
let lookahead = skip_trivia_lookahead(p, 1);
if p.peek_kind(lookahead) == SyntaxKind::EQ {
p.parse_shorthand_feature_member();
} else {
parse_stakeholder_usage(p);
}
}
SyntaxKind::OBJECTIVE_KW => {
let lookahead = skip_trivia_lookahead(p, 1);
if p.peek_kind(lookahead) == SyntaxKind::EQ {
p.parse_shorthand_feature_member();
} else {
parse_objective_usage(p);
}
}
SyntaxKind::ASSERT_KW => {
let next = p.peek_kind(1);
if next == SyntaxKind::NOT_KW || next == SyntaxKind::SATISFY_KW {
parse_requirement_verification(p);
} else {
parse_requirement_constraint(p);
}
}
SyntaxKind::ASSUME_KW | SyntaxKind::REQUIRE_KW => {
parse_requirement_constraint(p);
}
SyntaxKind::NOT_KW | SyntaxKind::SATISFY_KW | SyntaxKind::VERIFY_KW => {
parse_requirement_verification(p)
}
SyntaxKind::EXHIBIT_KW => parse_exhibit_usage(p),
SyntaxKind::INCLUDE_KW => parse_include_usage(p),
SyntaxKind::CONNECT_KW => p.parse_connect_usage(),
SyntaxKind::BINDING_KW | SyntaxKind::SUCCESSION_KW => p.parse_binding_or_succession(),
SyntaxKind::BIND_KW => parse_bind_usage(p),
SyntaxKind::ASSIGN_KW => parse_assign_action(p),
SyntaxKind::SPECIALIZATION_KW
| SyntaxKind::SUBCLASSIFIER_KW
| SyntaxKind::REDEFINITION_KW
| SyntaxKind::SUBSET_KW
| SyntaxKind::TYPING_KW
| SyntaxKind::CONJUGATION_KW
| SyntaxKind::DISJOINING_KW
| SyntaxKind::FEATURING_KW
| SyntaxKind::INVERTING_KW
| SyntaxKind::SUBTYPE_KW => {
parse_standalone_relationship(p);
}
SyntaxKind::VARIANT_KW => p.parse_variant_usage(),
SyntaxKind::EXPOSE_KW => parse_expose_statement(p),
SyntaxKind::REP_KW | SyntaxKind::LANGUAGE_KW => parse_textual_representation(p),
SyntaxKind::REDEFINES_KW
| SyntaxKind::COLON_GT_GT
| SyntaxKind::SUBSETS_KW
| SyntaxKind::COLON_GT => p.parse_redefines_feature_member(),
SyntaxKind::COLON | SyntaxKind::TYPED_KW => {
parse_anonymous_usage(p);
}
SyntaxKind::EQ => {
p.parse_shorthand_feature_member();
}
SyntaxKind::IDENT => p.parse_shorthand_feature_member(),
_ if p.at_name_token() => p.parse_shorthand_feature_member(),
_ => {
let got = if let Some(text) = p.current_token_text() {
format!("'{}'", text)
} else {
p.current_kind().display_name().to_string()
};
p.error_recover(
format!("unexpected {} in namespace body", got),
&[
SyntaxKind::PACKAGE_KW,
SyntaxKind::PART_KW,
SyntaxKind::R_BRACE,
],
);
}
}
}
pub(super) fn parse_prefix_metadata<P: SysMLParser>(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();
}