@@ -1510,7 +1510,7 @@ impl Compiler {
15101510 ..
15111511 } ) => {
15121512 if * is_star {
1513- self . compile_try_star_statement ( body, handlers, orelse, finalbody) ?
1513+ self . compile_try_star_except ( body, handlers, orelse, finalbody) ?
15141514 } else {
15151515 self . compile_try_statement ( body, handlers, orelse, finalbody) ?
15161516 }
@@ -2119,14 +2119,157 @@ impl Compiler {
21192119 Ok ( ( ) )
21202120 }
21212121
2122- fn compile_try_star_statement (
2122+ fn compile_try_star_except (
21232123 & mut self ,
2124- _body : & [ Stmt ] ,
2125- _handlers : & [ ExceptHandler ] ,
2126- _orelse : & [ Stmt ] ,
2127- _finalbody : & [ Stmt ] ,
2124+ body : & [ Stmt ] ,
2125+ handlers : & [ ExceptHandler ] ,
2126+ orelse : & [ Stmt ] ,
2127+ finalbody : & [ Stmt ] ,
21282128 ) -> CompileResult < ( ) > {
2129- Err ( self . error ( CodegenErrorType :: NotImplementedYet ) )
2129+ // Simplified except* implementation using CheckEgMatch
2130+ let handler_block = self . new_block ( ) ;
2131+ let finally_block = self . new_block ( ) ;
2132+
2133+ if !finalbody. is_empty ( ) {
2134+ emit ! (
2135+ self ,
2136+ Instruction :: SetupFinally {
2137+ handler: finally_block,
2138+ }
2139+ ) ;
2140+ }
2141+
2142+ let else_block = self . new_block ( ) ;
2143+
2144+ emit ! (
2145+ self ,
2146+ Instruction :: SetupExcept {
2147+ handler: handler_block,
2148+ }
2149+ ) ;
2150+ self . compile_statements ( body) ?;
2151+ emit ! ( self , Instruction :: PopBlock ) ;
2152+ emit ! ( self , Instruction :: Jump { target: else_block } ) ;
2153+
2154+ self . switch_to_block ( handler_block) ;
2155+ // Stack: [exc]
2156+
2157+ for handler in handlers {
2158+ let ExceptHandler :: ExceptHandler ( ExceptHandlerExceptHandler {
2159+ type_, name, body, ..
2160+ } ) = handler;
2161+
2162+ let skip_block = self . new_block ( ) ;
2163+ let next_block = self . new_block ( ) ;
2164+
2165+ // Compile exception type
2166+ if let Some ( exc_type) = type_ {
2167+ // Check for unparenthesized tuple (e.g., `except* A, B:` instead of `except* (A, B):`)
2168+ if let Expr :: Tuple ( ExprTuple { elts, range, .. } ) = exc_type. as_ref ( )
2169+ && let Some ( first) = elts. first ( )
2170+ && range. start ( ) . to_u32 ( ) == first. range ( ) . start ( ) . to_u32 ( )
2171+ {
2172+ return Err ( self . error ( CodegenErrorType :: SyntaxError (
2173+ "multiple exception types must be parenthesized" . to_owned ( ) ,
2174+ ) ) ) ;
2175+ }
2176+ self . compile_expression ( exc_type) ?;
2177+ } else {
2178+ return Err ( self . error ( CodegenErrorType :: SyntaxError (
2179+ "except* must specify an exception type" . to_owned ( ) ,
2180+ ) ) ) ;
2181+ }
2182+ // Stack: [exc, type]
2183+
2184+ emit ! ( self , Instruction :: CheckEgMatch ) ;
2185+ // Stack: [rest, match]
2186+
2187+ // Check if match is None (truthy check)
2188+ emit ! ( self , Instruction :: CopyItem { index: 1 } ) ;
2189+ emit ! ( self , Instruction :: ToBool ) ;
2190+ emit ! ( self , Instruction :: PopJumpIfFalse { target: skip_block } ) ;
2191+
2192+ // Handler matched - store match to name if provided
2193+ // Stack: [rest, match]
2194+ if let Some ( alias) = name {
2195+ self . store_name ( alias. as_str ( ) ) ?;
2196+ } else {
2197+ emit ! ( self , Instruction :: PopTop ) ;
2198+ }
2199+ // Stack: [rest]
2200+
2201+ self . compile_statements ( body) ?;
2202+
2203+ if let Some ( alias) = name {
2204+ self . emit_load_const ( ConstantData :: None ) ;
2205+ self . store_name ( alias. as_str ( ) ) ?;
2206+ self . compile_name ( alias. as_str ( ) , NameUsage :: Delete ) ?;
2207+ }
2208+
2209+ emit ! ( self , Instruction :: Jump { target: next_block } ) ;
2210+
2211+ // No match - pop match (None) and continue with rest
2212+ self . switch_to_block ( skip_block) ;
2213+ emit ! ( self , Instruction :: PopTop ) ; // drop match (None)
2214+ // Stack: [rest]
2215+
2216+ self . switch_to_block ( next_block) ;
2217+ // Stack: [rest] - continue with rest for next handler
2218+ }
2219+
2220+ let handled_block = self . new_block ( ) ;
2221+
2222+ // Check if remainder is truthy (has unhandled exceptions)
2223+ // Stack: [rest]
2224+ emit ! ( self , Instruction :: CopyItem { index: 1 } ) ;
2225+ emit ! ( self , Instruction :: ToBool ) ;
2226+ emit ! (
2227+ self ,
2228+ Instruction :: PopJumpIfFalse {
2229+ target: handled_block
2230+ }
2231+ ) ;
2232+ // Reraise unhandled exceptions
2233+ emit ! (
2234+ self ,
2235+ Instruction :: Raise {
2236+ kind: bytecode:: RaiseKind :: Raise
2237+ }
2238+ ) ;
2239+
2240+ // All exceptions handled
2241+ self . switch_to_block ( handled_block) ;
2242+ emit ! ( self , Instruction :: PopTop ) ; // drop remainder (None)
2243+ emit ! ( self , Instruction :: PopException ) ;
2244+
2245+ if !finalbody. is_empty ( ) {
2246+ emit ! ( self , Instruction :: PopBlock ) ;
2247+ emit ! ( self , Instruction :: EnterFinally ) ;
2248+ }
2249+
2250+ emit ! (
2251+ self ,
2252+ Instruction :: Jump {
2253+ target: finally_block,
2254+ }
2255+ ) ;
2256+
2257+ // try-else path
2258+ self . switch_to_block ( else_block) ;
2259+ self . compile_statements ( orelse) ?;
2260+
2261+ if !finalbody. is_empty ( ) {
2262+ emit ! ( self , Instruction :: PopBlock ) ;
2263+ emit ! ( self , Instruction :: EnterFinally ) ;
2264+ }
2265+
2266+ self . switch_to_block ( finally_block) ;
2267+ if !finalbody. is_empty ( ) {
2268+ self . compile_statements ( finalbody) ?;
2269+ emit ! ( self , Instruction :: EndFinally ) ;
2270+ }
2271+
2272+ Ok ( ( ) )
21302273 }
21312274
21322275 fn is_forbidden_arg_name ( name : & str ) -> bool {
0 commit comments