Skip to content

Commit

Permalink
add consecutive comperison operators to parser
Browse files Browse the repository at this point in the history
  • Loading branch information
dean-starkware committed Sep 19, 2024
1 parent 3eb7af7 commit cee3908
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 0 deletions.
7 changes: 7 additions & 0 deletions crates/cairo-lang-parser/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub enum ParserDiagnosticKind {
AttributesWithoutImplItem,
AttributesWithoutStatement,
DisallowedTrailingSeparatorOr,
ConsecutiveMathOperators { first_op: SyntaxKind, second_op: SyntaxKind },
}
impl DiagnosticEntry for ParserDiagnostic {
type DbType = dyn FilesGroup;
Expand Down Expand Up @@ -124,6 +125,12 @@ Did you mean to write `{identifier}!{left}...{right}'?",
ParserDiagnosticKind::DisallowedTrailingSeparatorOr => {
"A trailing `|` is not allowed in an or-pattern.".to_string()
}
ParserDiagnosticKind::ConsecutiveMathOperators { first_op, second_op } => {
format!(
"Consecutive math operators are not allowed: '{}' followed by '{}'",
first_op, second_op
)
}
}
}

Expand Down
40 changes: 40 additions & 0 deletions crates/cairo-lang-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,29 @@ impl<'a> Parser<'a> {
}
}

/// Checks if the current token is a relational or equality operator (`<`, `>`, `<=`, `>=`,
/// `==`, or `!=`).
///
/// This function is used to determine if the given `SyntaxKind` represents a relational or
/// equality operator, which is commonly used in binary expressions.
///
/// # Parameters:
/// - `kind`: The `SyntaxKind` of the current token.
///
/// # Returns:
/// `true` if the token is a relational or equality operator, otherwise `false`.
fn is_comperison_operator(&self, kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::TerminalLT // <
| SyntaxKind::TerminalGT // >
| SyntaxKind::TerminalLE // <=
| SyntaxKind::TerminalGE // >=
| SyntaxKind::TerminalEqEq // ==
| SyntaxKind::TerminalNeq // !=
)
}

/// Returns a GreenId of a node with an Expr.* kind (see [syntax::node::ast::Expr])
/// or TryParseFailure if such an expression can't be parsed.
///
Expand All @@ -1099,6 +1122,7 @@ impl<'a> Parser<'a> {
lbrace_allowed: LbraceAllowed,
) -> TryParseResult<ExprGreen> {
let mut expr = self.try_parse_atom_or_unary(lbrace_allowed)?;
let mut child_op: Option<SyntaxKind> = None;
while let Some(precedence) = get_post_operator_precedence(self.peek().kind) {
if precedence >= parent_precedence {
return Ok(expr);
Expand All @@ -1112,6 +1136,22 @@ impl<'a> Parser<'a> {
let rbrack = self.parse_token::<TerminalRBrack>();
ExprIndexed::new_green(self.db, expr, lbrack, index_expr, rbrack).into()
} else {
let current_op = self.peek().kind;
if let Some(child_op_kind) = child_op {
if self.is_comperison_operator(child_op_kind)
&& self.is_comperison_operator(current_op)
{
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
kind: ParserDiagnosticKind::ConsecutiveMathOperators {
first_op: child_op_kind,
second_op: current_op,
},
span: TextSpan { start: self.offset, end: self.offset },
});
}
}
child_op = Some(self.peek().kind);
let op = self.parse_binary_operator();
let rhs = self.parse_expr_limited(precedence, lbrace_allowed);
ExprBinary::new_green(self.db, expr, op, rhs).into()
Expand Down
10 changes: 10 additions & 0 deletions crates/cairo-lang-parser/src/parser_test_data/full_trees/test1
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ error: Skipped tokens. Expected: parameter.
fn foo(,var1: int,, mut ref var2: felt252,) -> int {
^

error: Consecutive math operators are not allowed: 'TerminalEqEq' followed by 'TerminalEqEq'
--> src/parser_test_data/cairo_test_files/test1.cairo:15:20
let z = if 0 + x == y {
^

error: Missing token TerminalRBrace.
--> src/parser_test_data/cairo_test_files/test1.cairo:30:14
return x;
Expand Down Expand Up @@ -865,6 +870,11 @@ error: Skipped tokens. Expected: parameter.
fn foo(,var1: int,, mut ref var2: felt252,) -> int {
^

error: Consecutive math operators are not allowed: 'TerminalEqEq' followed by 'TerminalEqEq'
--> src/parser_test_data/cairo_test_files/test1.cairo:15:20
let z = if 0 + x == y {
^

error: Missing token TerminalRBrace.
--> src/parser_test_data/cairo_test_files/test1.cairo:30:14
return x;
Expand Down
34 changes: 34 additions & 0 deletions crates/cairo-lang-parser/src/parser_test_data/partial_trees/expr
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,37 @@ StatementExpr
│ ├── op (kind: TokenMul): '*'
│ └── rhs (kind: TokenLiteralNumber): '5'
└── semicolon (kind: OptionTerminalSemicolonEmpty) []

//! > ==========================================================================

//! > Test consecutive comparison operators
//! > test_runner_name
test_partial_parser_tree(expect_diagnostics: true)

//! > cairo_code
fn f() -> bool {
3 < 1 > 5
}

//! > top_level_kind
StatementExpr

//! > ignored_kinds

//! > expected_diagnostics
error: Consecutive comparison operators are not allowed: 'TerminalGT' followed by 'TerminalGT'
--> dummy_file.cairo:2:9
3 < 1 > 5
^

//! > expected_tree
└── Top level kind: StatementExpr
├── attributes (kind: AttributeList) []
├── expr (kind: ExprBinary)
│ ├── lhs (kind: ExprBinary)
│ │ ├── lhs (kind: TokenLiteralNumber): '3'
│ │ ├── op (kind: TokenLT): '<'
│ │ └── rhs (kind: TokenLiteralNumber): '1'
│ ├── op (kind: TokenGT): '>'
│ └── rhs (kind: TokenLiteralNumber): '5'
└── semicolon (kind: OptionTerminalSemicolonEmpty) []

0 comments on commit cee3908

Please sign in to comment.