use crate::parser::syntax_kind::SyntaxKind;
pub trait ExpressionParser {
fn current_kind(&self) -> SyntaxKind;
fn at(&self, kind: SyntaxKind) -> bool;
fn at_any(&self, kinds: &[SyntaxKind]) -> bool;
fn at_name_token(&self) -> bool;
fn get_pos(&self) -> usize;
fn peek_kind(&self, n: usize) -> SyntaxKind;
fn bump(&mut self);
fn bump_any(&mut self);
fn expect(&mut self, kind: SyntaxKind);
fn skip_trivia(&mut self);
fn start_node(&mut self, kind: SyntaxKind);
fn finish_node(&mut self);
fn parse_qualified_name(&mut self);
fn parse_argument(&mut self);
}
pub fn parse_expression<P: ExpressionParser>(p: &mut P) -> bool {
let start_pos = p.get_pos();
parse_conditional_expression(p);
p.get_pos() > start_pos
}
fn parse_ternary_conditional<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
parse_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::ELSE_KW) {
p.bump();
p.skip_trivia();
parse_expression(p);
}
}
fn parse_keyword_conditional<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
parse_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::ELSE_KW) {
p.bump();
p.skip_trivia();
parse_expression(p);
}
}
pub fn parse_conditional_expression<P: ExpressionParser>(p: &mut P) {
p.start_node(SyntaxKind::EXPRESSION);
if p.at(SyntaxKind::IF_KW) {
p.bump(); p.skip_trivia();
parse_null_coalescing_expression(p); p.skip_trivia();
if p.at(SyntaxKind::QUESTION) {
parse_ternary_conditional(p);
} else if p.at(SyntaxKind::THEN_KW) {
parse_keyword_conditional(p);
}
} else {
parse_null_coalescing_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::QUESTION) && !p.at(SyntaxKind::QUESTION_QUESTION) {
p.bump(); p.skip_trivia();
parse_expression(p); p.skip_trivia();
p.expect(SyntaxKind::COLON);
p.skip_trivia();
parse_expression(p); }
}
p.finish_node();
}
pub fn parse_null_coalescing_expression<P: ExpressionParser>(p: &mut P) {
parse_implies_expression(p);
while p.at(SyntaxKind::QUESTION_QUESTION) {
p.bump();
p.skip_trivia();
parse_implies_expression(p);
}
}
pub fn parse_implies_expression<P: ExpressionParser>(p: &mut P) {
parse_or_expression(p);
while p.at(SyntaxKind::IMPLIES_KW) {
p.bump();
p.skip_trivia();
parse_or_expression(p);
}
}
pub fn parse_or_expression<P: ExpressionParser>(p: &mut P) {
parse_xor_expression(p);
p.skip_trivia();
while p.at(SyntaxKind::PIPE) || p.at(SyntaxKind::OR_KW) {
p.bump();
p.skip_trivia();
parse_xor_expression(p);
p.skip_trivia();
}
}
pub fn parse_xor_expression<P: ExpressionParser>(p: &mut P) {
parse_and_expression(p);
p.skip_trivia();
while p.at(SyntaxKind::XOR_KW) {
p.bump();
p.skip_trivia();
parse_and_expression(p);
p.skip_trivia();
}
}
pub fn parse_and_expression<P: ExpressionParser>(p: &mut P) {
parse_equality_expression(p);
p.skip_trivia();
while p.at(SyntaxKind::AMP) || p.at(SyntaxKind::AND_KW) {
p.bump();
p.skip_trivia();
parse_equality_expression(p);
p.skip_trivia();
}
}
pub fn parse_equality_expression<P: ExpressionParser>(p: &mut P) {
parse_classification_expression(p);
p.skip_trivia();
while p.at_any(&[
SyntaxKind::EQ_EQ,
SyntaxKind::BANG_EQ,
SyntaxKind::EQ_EQ_EQ,
SyntaxKind::BANG_EQ_EQ,
]) {
p.bump();
p.skip_trivia();
parse_classification_expression(p);
p.skip_trivia();
}
}
pub fn parse_classification_expression<P: ExpressionParser>(p: &mut P) {
if p.at_any(&[SyntaxKind::HASTYPE_KW, SyntaxKind::ISTYPE_KW]) {
p.bump();
p.skip_trivia();
p.parse_qualified_name();
return;
}
parse_relational_expression(p);
p.skip_trivia();
if p.at_any(&[
SyntaxKind::HASTYPE_KW,
SyntaxKind::ISTYPE_KW,
SyntaxKind::AS_KW,
SyntaxKind::META_KW,
SyntaxKind::AT,
SyntaxKind::AT_AT,
]) {
p.bump();
p.skip_trivia();
p.parse_qualified_name();
}
}
pub fn parse_relational_expression<P: ExpressionParser>(p: &mut P) {
parse_range_expression(p);
p.skip_trivia();
while p.at_any(&[
SyntaxKind::LT,
SyntaxKind::GT,
SyntaxKind::LT_EQ,
SyntaxKind::GT_EQ,
]) {
p.bump();
p.skip_trivia();
parse_range_expression(p);
p.skip_trivia();
}
}
pub fn parse_range_expression<P: ExpressionParser>(p: &mut P) {
parse_additive_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::DOT_DOT) {
p.bump();
p.skip_trivia();
parse_additive_expression(p);
}
}
pub fn parse_additive_expression<P: ExpressionParser>(p: &mut P) {
parse_multiplicative_expression(p);
while p.at(SyntaxKind::PLUS) || p.at(SyntaxKind::MINUS) {
p.bump();
p.skip_trivia();
parse_multiplicative_expression(p);
}
}
pub fn parse_multiplicative_expression<P: ExpressionParser>(p: &mut P) {
parse_exponentiation_expression(p);
while p.at_any(&[SyntaxKind::STAR, SyntaxKind::SLASH, SyntaxKind::PERCENT]) {
p.bump();
p.skip_trivia();
parse_exponentiation_expression(p);
}
}
pub fn parse_exponentiation_expression<P: ExpressionParser>(p: &mut P) {
parse_unary_expression(p);
p.skip_trivia();
if p.at(SyntaxKind::STAR_STAR) || p.at(SyntaxKind::CARET) {
p.bump();
p.skip_trivia();
parse_exponentiation_expression(p);
}
}
pub fn parse_unary_expression<P: ExpressionParser>(p: &mut P) {
if p.at_any(&[
SyntaxKind::PLUS,
SyntaxKind::MINUS,
SyntaxKind::TILDE,
SyntaxKind::NOT_KW,
]) {
p.bump();
p.skip_trivia();
}
parse_extent_expression(p);
}
pub fn parse_extent_expression<P: ExpressionParser>(p: &mut P) {
if p.at(SyntaxKind::ALL_KW) {
p.bump();
p.skip_trivia();
}
parse_primary_expression(p);
}
fn handle_feature_chain<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if p.at(SyntaxKind::IDENT) || p.at(SyntaxKind::THIS_KW) {
p.bump();
p.skip_trivia();
if p.at(SyntaxKind::L_PAREN) {
parse_argument_list(p);
}
}
}
fn handle_shorthand_select<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
p.bump(); p.skip_trivia();
if p.at(SyntaxKind::L_BRACE) {
parse_arrow_body(p);
}
}
fn handle_shorthand_collect<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
parse_arrow_body(p);
}
fn handle_arrow_invocation<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if p.at(SyntaxKind::IDENT) {
p.bump();
}
p.skip_trivia();
if p.at(SyntaxKind::L_BRACE) {
parse_arrow_body(p);
} else if p.at(SyntaxKind::L_PAREN) {
parse_argument_list(p);
} else if !p.at(SyntaxKind::SEMICOLON)
&& !p.at(SyntaxKind::R_BRACE)
&& !p.at(SyntaxKind::R_PAREN)
{
if p.at(SyntaxKind::STRING) || p.at(SyntaxKind::IDENT) || p.at(SyntaxKind::INTEGER) {
parse_expression(p);
}
}
}
fn handle_bracket_index<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if p.at(SyntaxKind::L_PAREN) {
p.bump(); p.skip_trivia();
parse_expression(p);
p.skip_trivia();
while p.at(SyntaxKind::COMMA) {
p.bump();
p.skip_trivia();
parse_expression(p);
p.skip_trivia();
}
p.expect(SyntaxKind::R_PAREN);
}
}
fn handle_array_index<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
parse_expression(p);
p.skip_trivia();
p.expect(SyntaxKind::R_BRACKET);
}
pub fn parse_primary_expression<P: ExpressionParser>(p: &mut P) {
parse_base_expression(p);
loop {
p.skip_trivia();
match p.current_kind() {
SyntaxKind::DOT => {
if p.peek_kind(1) == SyntaxKind::QUESTION {
handle_shorthand_select(p);
} else if p.peek_kind(1) == SyntaxKind::L_BRACE {
handle_shorthand_collect(p);
} else {
handle_feature_chain(p);
}
}
SyntaxKind::ARROW => handle_arrow_invocation(p),
SyntaxKind::HASH => handle_bracket_index(p),
SyntaxKind::L_BRACKET => handle_array_index(p),
_ => break,
}
}
}
fn looks_like_typed_parameter<P: ExpressionParser>(p: &P) -> bool {
let mut lookahead = 1;
while matches!(
p.peek_kind(lookahead),
SyntaxKind::WHITESPACE | SyntaxKind::LINE_COMMENT | SyntaxKind::BLOCK_COMMENT
) {
lookahead += 1;
}
if p.peek_kind(lookahead) != SyntaxKind::COLON {
return false;
}
lookahead += 1;
while matches!(
p.peek_kind(lookahead),
SyntaxKind::WHITESPACE | SyntaxKind::LINE_COMMENT | SyntaxKind::BLOCK_COMMENT
) {
lookahead += 1;
}
if !matches!(p.peek_kind(lookahead), SyntaxKind::IDENT) {
return false;
}
lookahead += 1;
loop {
while matches!(
p.peek_kind(lookahead),
SyntaxKind::WHITESPACE | SyntaxKind::LINE_COMMENT | SyntaxKind::BLOCK_COMMENT
) {
lookahead += 1;
}
if p.peek_kind(lookahead) == SyntaxKind::COLON_COLON {
lookahead += 1;
while matches!(
p.peek_kind(lookahead),
SyntaxKind::WHITESPACE | SyntaxKind::LINE_COMMENT | SyntaxKind::BLOCK_COMMENT
) {
lookahead += 1;
}
if matches!(p.peek_kind(lookahead), SyntaxKind::IDENT) {
lookahead += 1;
}
} else {
break;
}
}
while matches!(
p.peek_kind(lookahead),
SyntaxKind::WHITESPACE | SyntaxKind::LINE_COMMENT | SyntaxKind::BLOCK_COMMENT
) {
lookahead += 1;
}
p.peek_kind(lookahead) == SyntaxKind::SEMICOLON
}
fn handle_visibility_prefix<P: ExpressionParser>(p: &mut P) {
if p.at_any(&[
SyntaxKind::PRIVATE_KW,
SyntaxKind::PUBLIC_KW,
SyntaxKind::PROTECTED_KW,
]) {
p.bump();
p.skip_trivia();
}
}
fn parse_nested_body_members<P: ExpressionParser>(p: &mut P) {
while !p.at(SyntaxKind::R_BRACE) && p.current_kind() != SyntaxKind::__LAST {
if p.at(SyntaxKind::DOC_KW) || p.at(SyntaxKind::COMMENT_KW) {
p.bump();
p.skip_trivia();
while !p.at(SyntaxKind::R_BRACE)
&& p.current_kind() != SyntaxKind::__LAST
&& !p.at(SyntaxKind::DOC_KW)
&& !p.at(SyntaxKind::COMMENT_KW)
{
p.bump_any();
p.skip_trivia();
}
} else {
break;
}
}
}
fn parse_parameter_body<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
parse_nested_body_members(p);
p.expect(SyntaxKind::R_BRACE);
p.skip_trivia();
}
fn handle_usage_keyword<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if p.at_name_token() {
p.bump();
p.skip_trivia();
}
if p.at(SyntaxKind::COLON) {
p.bump();
p.skip_trivia();
p.parse_qualified_name();
p.skip_trivia();
}
if p.at(SyntaxKind::EQ) {
p.bump();
p.skip_trivia();
parse_expression(p);
p.skip_trivia();
}
if p.at(SyntaxKind::L_BRACE) {
p.bump();
p.skip_trivia();
while !p.at(SyntaxKind::R_BRACE) && p.current_kind() != SyntaxKind::__LAST {
if p.at_any(&[
SyntaxKind::DOC_KW,
SyntaxKind::COMMENT_KW,
SyntaxKind::COLON_GT_GT,
SyntaxKind::COLON_GT,
]) {
p.bump();
p.skip_trivia();
if p.at_name_token() {
p.bump();
p.skip_trivia();
}
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
p.skip_trivia();
}
} else {
p.bump_any();
p.skip_trivia();
}
}
p.expect(SyntaxKind::R_BRACE);
p.skip_trivia();
} else if p.at(SyntaxKind::SEMICOLON) {
p.bump();
p.skip_trivia();
}
}
fn handle_feature_declaration<P: ExpressionParser>(p: &mut P) -> bool {
if !p.at_name_token() {
return false;
}
let mut lookahead = 1;
while matches!(
p.peek_kind(lookahead),
SyntaxKind::WHITESPACE | SyntaxKind::LINE_COMMENT | SyntaxKind::BLOCK_COMMENT
) {
lookahead += 1;
}
if p.peek_kind(lookahead) != SyntaxKind::COLON {
return false;
}
p.bump(); p.skip_trivia();
p.bump(); p.skip_trivia();
p.parse_qualified_name();
p.skip_trivia();
if p.at(SyntaxKind::EQ) {
p.bump();
p.skip_trivia();
parse_expression(p);
p.skip_trivia();
}
if p.at(SyntaxKind::SEMICOLON) {
p.bump();
p.skip_trivia();
}
true
}
fn parse_in_parameter<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if p.at(SyntaxKind::REF_KW) {
p.bump();
p.skip_trivia();
}
if p.at_name_token() {
p.bump();
}
p.skip_trivia();
if p.at(SyntaxKind::COLON) || p.at(SyntaxKind::COLON_GT) {
p.bump();
p.skip_trivia();
p.parse_qualified_name();
}
p.skip_trivia();
if p.at(SyntaxKind::L_BRACE) {
parse_parameter_body(p);
} else if p.at(SyntaxKind::SEMICOLON) {
p.bump();
p.skip_trivia();
}
}
fn parse_implicit_parameter<P: ExpressionParser>(p: &mut P) -> bool {
if !looks_like_typed_parameter(p) {
return false;
}
p.bump(); p.skip_trivia();
p.bump(); p.skip_trivia();
p.parse_qualified_name();
p.skip_trivia();
p.bump(); p.skip_trivia();
true
}
pub fn parse_arrow_body<P: ExpressionParser>(p: &mut P) {
p.expect(SyntaxKind::L_BRACE);
p.skip_trivia();
let token_count = 10000;
let mut iterations = 0;
while !p.at(SyntaxKind::R_BRACE) && iterations < token_count {
iterations += 1;
let _start_pos = p.get_pos();
if p.at(SyntaxKind::DOC_KW) || p.at(SyntaxKind::COMMENT_KW) {
p.bump();
p.skip_trivia();
continue;
}
handle_visibility_prefix(p);
if p.at_any(&[
SyntaxKind::ATTRIBUTE_KW,
SyntaxKind::ITEM_KW,
SyntaxKind::PART_KW,
]) {
handle_usage_keyword(p);
continue;
}
if handle_feature_declaration(p) {
continue;
}
if p.at(SyntaxKind::IN_KW) {
parse_in_parameter(p);
continue;
}
if p.at_name_token() && parse_implicit_parameter(p) {
continue;
}
parse_expression(p);
p.skip_trivia();
if p.get_pos() == _start_pos && !p.at(SyntaxKind::R_BRACE) {
p.bump_any();
}
}
p.expect(SyntaxKind::R_BRACE);
}
fn parse_literal<P: ExpressionParser>(p: &mut P) -> bool {
if p.at_any(&[
SyntaxKind::INTEGER,
SyntaxKind::DECIMAL,
SyntaxKind::STRING,
SyntaxKind::TRUE_KW,
SyntaxKind::FALSE_KW,
SyntaxKind::NULL_KW,
]) {
p.bump();
true
} else {
false
}
}
fn parse_instantiation<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
p.parse_qualified_name();
p.skip_trivia();
if p.at(SyntaxKind::L_PAREN) {
parse_argument_list(p);
}
}
fn parse_block_expression<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if !p.at(SyntaxKind::R_BRACE) {
parse_expression(p);
}
p.skip_trivia();
p.expect(SyntaxKind::R_BRACE);
}
fn parse_parenthesized_expression<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
if !p.at(SyntaxKind::R_PAREN) {
parse_expression(p);
while p.at(SyntaxKind::COMMA) {
p.bump();
p.skip_trivia();
parse_expression(p);
p.skip_trivia();
}
}
p.skip_trivia();
p.expect(SyntaxKind::R_PAREN);
}
fn is_feature_reference_token(kind: SyntaxKind) -> bool {
!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
| SyntaxKind::TRUE_KW
| SyntaxKind::FALSE_KW
| SyntaxKind::NULL_KW
)
}
fn parse_feature_reference<P: ExpressionParser>(p: &mut P) {
p.parse_qualified_name();
p.skip_trivia();
if p.at(SyntaxKind::L_PAREN) {
parse_argument_list(p);
}
}
fn parse_metadata_access<P: ExpressionParser>(p: &mut P) {
p.bump(); p.skip_trivia();
p.parse_qualified_name();
}
pub fn parse_base_expression<P: ExpressionParser>(p: &mut P) {
p.skip_trivia();
match p.current_kind() {
kind if parse_literal(p) => {}
SyntaxKind::NEW_KW => parse_instantiation(p),
SyntaxKind::L_BRACE => parse_block_expression(p),
SyntaxKind::L_PAREN => parse_parenthesized_expression(p),
kind if is_feature_reference_token(kind) => parse_feature_reference(p),
SyntaxKind::AT => parse_metadata_access(p),
_ => {}
}
}
pub fn parse_argument_list<P: ExpressionParser>(p: &mut P) {
p.start_node(SyntaxKind::ARGUMENT_LIST);
p.expect(SyntaxKind::L_PAREN);
p.skip_trivia();
if !p.at(SyntaxKind::R_PAREN) {
parse_argument_via_trait(p);
p.skip_trivia();
while p.at(SyntaxKind::COMMA) {
p.bump();
p.skip_trivia();
parse_argument_via_trait(p);
p.skip_trivia();
}
}
p.expect(SyntaxKind::R_PAREN);
p.finish_node();
}
fn parse_argument_via_trait<P: ExpressionParser>(p: &mut P) {
p.parse_argument();
}
pub fn parse_argument<P: ExpressionParser>(p: &mut P) {
p.start_node(SyntaxKind::ARGUMENT_LIST);
if p.at(SyntaxKind::IDENT) {
let next = p.peek_kind(1);
if next == SyntaxKind::EQ {
p.bump(); p.skip_trivia();
p.bump(); p.skip_trivia();
}
}
parse_expression(p);
p.finish_node();
}