@@ -76,6 +76,9 @@ pub enum Token {
7676 StarEq ,
7777 SlashEq ,
7878 PercentEq ,
79+ StarStarEq ,
80+ // Exponentiation operator
81+ StarStar ,
7982 Ne ,
8083 Lt ,
8184 Le ,
@@ -515,6 +518,14 @@ impl Lexer {
515518 }
516519 Some ( '*' ) => {
517520 self . advance ( ) ;
521+ if self . current ( ) == Some ( '*' ) {
522+ self . advance ( ) ;
523+ if self . current ( ) == Some ( '=' ) {
524+ self . advance ( ) ;
525+ return Token :: StarStarEq ;
526+ }
527+ return Token :: StarStar ;
528+ }
518529 if self . current ( ) == Some ( '=' ) {
519530 self . advance ( ) ;
520531 return Token :: StarEq ;
@@ -1045,9 +1056,9 @@ impl Parser {
10451056 } )
10461057 }
10471058 Token :: PlusEq | Token :: MinusEq | Token :: StarEq
1048- | Token :: SlashEq | Token :: PercentEq => {
1059+ | Token :: SlashEq | Token :: PercentEq | Token :: StarStarEq => {
10491060 // Desugar `x += expr` → `x = x + expr`. Same
1050- // for -=, *=, /=, %=. We don't introduce a new
1061+ // for -=, *=, /=, %=, **= . We don't introduce a new
10511062 // AST node — the rewrite stays inside the parser
10521063 // and the rest of the pipeline sees a normal
10531064 // Assignment with a binop on the RHS.
@@ -1062,6 +1073,7 @@ impl Parser {
10621073 Token :: StarEq => Expression :: Mul ( Box :: new ( lhs) , Box :: new ( rhs) ) ,
10631074 Token :: SlashEq => Expression :: Div ( Box :: new ( lhs) , Box :: new ( rhs) ) ,
10641075 Token :: PercentEq => Expression :: Mod ( Box :: new ( lhs) , Box :: new ( rhs) ) ,
1076+ Token :: StarStarEq => Expression :: Power ( Box :: new ( lhs) , Box :: new ( rhs) ) ,
10651077 _ => unreachable ! ( ) ,
10661078 } ;
10671079 Ok ( Statement :: Assignment { name : ident, value } )
@@ -1745,23 +1757,23 @@ impl Parser {
17451757 }
17461758
17471759 fn parse_multiplicative ( & mut self ) -> Result < Expression , String > {
1748- let mut left = self . parse_primary ( ) ?;
1760+ let mut left = self . parse_power ( ) ?;
17491761
17501762 while matches ! ( self . current( ) , Token :: Star | Token :: Slash | Token :: Percent ) {
17511763 let expr = match self . current ( ) {
17521764 Token :: Star => {
17531765 self . advance ( ) ;
1754- let right = self . parse_primary ( ) ?;
1766+ let right = self . parse_power ( ) ?;
17551767 Expression :: mul ( left, right)
17561768 }
17571769 Token :: Slash => {
17581770 self . advance ( ) ;
1759- let right = self . parse_primary ( ) ?;
1771+ let right = self . parse_power ( ) ?;
17601772 Expression :: div ( left, right)
17611773 }
17621774 Token :: Percent => {
17631775 self . advance ( ) ;
1764- let right = self . parse_primary ( ) ?;
1776+ let right = self . parse_power ( ) ?;
17651777 Expression :: Mod ( Box :: new ( left) , Box :: new ( right) )
17661778 }
17671779 _ => break ,
@@ -1772,6 +1784,18 @@ impl Parser {
17721784 Ok ( left)
17731785 }
17741786
1787+ // Right-associative: `a ** b ** c` = `a ** (b ** c)`
1788+ fn parse_power ( & mut self ) -> Result < Expression , String > {
1789+ let base = self . parse_primary ( ) ?;
1790+ if self . current ( ) == Token :: StarStar {
1791+ self . advance ( ) ;
1792+ let exp = self . parse_power ( ) ?; // right-assoc: recurse
1793+ Ok ( Expression :: Power ( Box :: new ( base) , Box :: new ( exp) ) )
1794+ } else {
1795+ Ok ( base)
1796+ }
1797+ }
1798+
17751799 fn parse_primary ( & mut self ) -> Result < Expression , String > {
17761800 // Unary bitwise NOT: `~x`
17771801 if self . current ( ) == Token :: BitNot {
0 commit comments