Repository: swc-project/swc
File: crates/swc_es_parser/src/lexer.rs (Rust)

Code before:
        Token::simple(
            kind,
            Span::new_with_checked(start, self.input.cur_pos()),
            had_line_break_before,
        )
    }

    fn gt_like(&mut self, had_line_break_before: bool) -> Token {
        let start = self.input.cur_pos();
        self.bump_ascii();
        let kind = if self.input.eat_byte(b'=') {
            TokenKind::GtEq
        } else {
            TokenKind::Gt
        };
        Token::simple(
            kind,
            Span::new_with_checked(start, self.input.cur_pos()),
            had_line_break_before,
        )
    }

    fn binary_or_assign(
        &mut self,
        plain: TokenKind,
        assign: TokenKind,
        had_line_break_before: bool,
    ) -> Token {
        let start = self.input.cur_pos();
        self.bump_ascii();
        let kind = if self.input.eat_byte(b'=') {
            assign
        } else {
            plain
        };
        Token::simple(
            kind,
            Span::new_with_checked(start, self.input.cur_pos()),
            had_line_break_before,
        )
    }

    fn one(&mut self, kind: TokenKind, had_line_break_before: bool) -> Token {
        let start = self.input.cur_pos();
        self.bump_ascii();
        Token::simple(
            kind,
            Span::new_with_checked(start, self.input.cur_pos()),
            had_line_break_before,
        )
    }

Review comment (bug):
The lexer now emits combined shift tokens (`LtLt`, `GtGt`, `GtGtGt`, and their `*Eq` forms), but the parser currently has no shift-expression precedence level and no handling for these token kinds. As a result, valid shift expressions like `a << b` / `a >> b` will fail to parse. Consider adding shift-expression parsing support before switching the lexer to these combined tokens (or keep lexing them as `<`/`>` sequences until the parser is updated).

Code after:
            TokenKind::LtEq
        } else {
            TokenKind::Lt
        };
        Token::simple(
            kind,
            Span::new_with_checked(start, self.input.cur_pos()),
            had_line_break_before,
        )
    }

    fn gt_like(&mut self, had_line_break_before: bool) -> Token {
        let start = self.input.cur_pos();
        self.bump_ascii();
        let kind = if self.input.eat_byte(b'>') {
            if self.input.eat_byte(b'>') {
                if self.input.eat_byte(b'=') {
                    TokenKind::GtGtGtEq
                } else {
                    TokenKind::GtGtGt
                }
            } else if self.input.eat_byte(b'=') {
                TokenKind::GtGtEq
            } else {
                TokenKind::GtGt
            }
        } else if self.input.eat_byte(b'=') {
            TokenKind::GtEq
        } else {
            TokenKind::Gt
        };
        Token::simple(
            kind,
            Span::new_with_checked(start, self.input.cur_pos()),
            had_line_break_before,
        )
    }

    fn binary_or_assign(
        &mut self,
        plain: TokenKind,
        assign: TokenKind,
        had_line_break_before: bool,
    ) -> Token {
        let start = self.input.cur_pos();
        self.bump_ascii();
        let kind = if self.input.eat_byte(b'=') {
            assign
        } else {
            plain
        };