@@ -1052,9 +1052,14 @@ stack_effect(int opcode, int oparg, int jump)
1052
1052
* This is the main reason of using this opcode instead of
1053
1053
* "LOAD_CONST None". */
1054
1054
return 6 ;
1055
+ case RERAISE :
1056
+ return -3 ;
1055
1057
case CALL_FINALLY :
1056
1058
return jump ? 1 : 0 ;
1057
1059
1060
+ case WITH_EXCEPT_START :
1061
+ return 1 ;
1062
+
1058
1063
case LOAD_FAST :
1059
1064
return 1 ;
1060
1065
case STORE_FAST :
@@ -1490,6 +1495,15 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
1490
1495
assert (u -> u_fblock [u -> u_nfblocks ].fb_block == b );
1491
1496
}
1492
1497
1498
+ static int
1499
+ compiler_call_exit_with_nones (struct compiler * c ) {
1500
+ ADDOP_O (c , LOAD_CONST , Py_None , consts );
1501
+ ADDOP (c , DUP_TOP );
1502
+ ADDOP (c , DUP_TOP );
1503
+ ADDOP_I (c , CALL_FUNCTION , 3 );
1504
+ return 1 ;
1505
+ }
1506
+
1493
1507
/* Unwind a frame block. If preserve_tos is true, the TOS before
1494
1508
* popping the blocks will be restored afterwards.
1495
1509
*/
@@ -1528,15 +1542,15 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
1528
1542
if (preserve_tos ) {
1529
1543
ADDOP (c , ROT_TWO );
1530
1544
}
1531
- ADDOP (c , BEGIN_FINALLY );
1532
- ADDOP (c , WITH_CLEANUP_START );
1545
+ if (!compiler_call_exit_with_nones (c )) {
1546
+ return 0 ;
1547
+ }
1533
1548
if (info -> fb_type == ASYNC_WITH ) {
1534
1549
ADDOP (c , GET_AWAITABLE );
1535
1550
ADDOP_O (c , LOAD_CONST , Py_None , consts );
1536
1551
ADDOP (c , YIELD_FROM );
1537
1552
}
1538
- ADDOP (c , WITH_CLEANUP_FINISH );
1539
- ADDOP_I (c , POP_FINALLY , 0 );
1553
+ ADDOP (c , POP_TOP );
1540
1554
return 1 ;
1541
1555
1542
1556
case HANDLER_CLEANUP :
@@ -4310,6 +4324,22 @@ expr_constant(expr_ty e)
4310
4324
return -1 ;
4311
4325
}
4312
4326
4327
+ static int
4328
+ compiler_with_except_finish (struct compiler * c ) {
4329
+ basicblock * exit ;
4330
+ exit = compiler_new_block (c );
4331
+ if (exit == NULL )
4332
+ return 0 ;
4333
+ ADDOP_JABS (c , POP_JUMP_IF_TRUE , exit );
4334
+ ADDOP (c , RERAISE );
4335
+ compiler_use_next_block (c , exit );
4336
+ ADDOP (c , POP_TOP );
4337
+ ADDOP (c , POP_TOP );
4338
+ ADDOP (c , POP_TOP );
4339
+ ADDOP (c , POP_EXCEPT );
4340
+ ADDOP (c , POP_TOP );
4341
+ return 1 ;
4342
+ }
4313
4343
4314
4344
/*
4315
4345
Implements the async with statement.
@@ -4338,14 +4368,16 @@ expr_constant(expr_ty e)
4338
4368
static int
4339
4369
compiler_async_with (struct compiler * c , stmt_ty s , int pos )
4340
4370
{
4341
- basicblock * block , * finally ;
4371
+ basicblock * block , * final1 , * final2 , * exit ;
4342
4372
withitem_ty item = asdl_seq_GET (s -> v .AsyncWith .items , pos );
4343
4373
4344
4374
assert (s -> kind == AsyncWith_kind );
4345
4375
4346
4376
block = compiler_new_block (c );
4347
- finally = compiler_new_block (c );
4348
- if (!block || !finally )
4377
+ final1 = compiler_new_block (c );
4378
+ final2 = compiler_new_block (c );
4379
+ exit = compiler_new_block (c );
4380
+ if (!block || !final1 || !final2 || !exit )
4349
4381
return 0 ;
4350
4382
4351
4383
/* Evaluate EXPR */
@@ -4356,11 +4388,11 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
4356
4388
ADDOP_O (c , LOAD_CONST , Py_None , consts );
4357
4389
ADDOP (c , YIELD_FROM );
4358
4390
4359
- ADDOP_JREL (c , SETUP_ASYNC_WITH , finally );
4391
+ ADDOP_JREL (c , SETUP_ASYNC_WITH , final2 );
4360
4392
4361
4393
/* SETUP_ASYNC_WITH pushes a finally block. */
4362
4394
compiler_use_next_block (c , block );
4363
- if (!compiler_push_fblock (c , ASYNC_WITH , block , finally )) {
4395
+ if (!compiler_push_fblock (c , ASYNC_WITH , block , final2 )) {
4364
4396
return 0 ;
4365
4397
}
4366
4398
@@ -4381,74 +4413,88 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
4381
4413
4382
4414
/* End of try block; start the finally block */
4383
4415
ADDOP (c , POP_BLOCK );
4384
- ADDOP (c , BEGIN_FINALLY );
4385
4416
compiler_pop_fblock (c , ASYNC_WITH , block );
4386
4417
4387
- compiler_use_next_block (c , finally );
4388
- if (!compiler_push_fblock (c , FINALLY_END , finally , NULL ))
4418
+ compiler_use_next_block (c , final1 );
4419
+ if (!compiler_push_fblock (c , FINALLY_END , final1 , NULL ))
4389
4420
return 0 ;
4390
4421
4391
- /* Finally block starts; context.__exit__ is on the stack under
4392
- the exception or return information. Just issue our magic
4393
- opcode. */
4394
- ADDOP (c , WITH_CLEANUP_START );
4422
+ /* `finally` block for successful outcome:
4423
+ * call __exit__(None, None, None)
4424
+ */
4425
+ if (!compiler_call_exit_with_nones (c ))
4426
+ return 0 ;
4427
+ ADDOP (c , GET_AWAITABLE );
4428
+ ADDOP_O (c , LOAD_CONST , Py_None , consts );
4429
+ ADDOP (c , YIELD_FROM );
4430
+
4431
+ ADDOP (c , POP_TOP );
4432
+
4433
+ compiler_pop_fblock (c , FINALLY_END , final1 );
4434
+ ADDOP_JABS (c , JUMP_ABSOLUTE , exit );
4435
+
4436
+ /* `finally` block for exceptional outcome */
4437
+ compiler_use_next_block (c , final2 );
4438
+ if (!compiler_push_fblock (c , FINALLY_END , final2 , NULL ))
4439
+ return 0 ;
4395
4440
4441
+ ADDOP (c , WITH_EXCEPT_START );
4396
4442
ADDOP (c , GET_AWAITABLE );
4397
4443
ADDOP_O (c , LOAD_CONST , Py_None , consts );
4398
4444
ADDOP (c , YIELD_FROM );
4445
+ compiler_with_except_finish (c );
4399
4446
4400
- ADDOP (c , WITH_CLEANUP_FINISH );
4447
+ compiler_pop_fblock (c , FINALLY_END , final2 );
4401
4448
4402
- /* Finally block ends. */
4403
- ADDOP (c , END_FINALLY );
4404
- compiler_pop_fblock (c , FINALLY_END , finally );
4449
+ compiler_use_next_block (c , exit );
4405
4450
return 1 ;
4406
4451
}
4407
4452
4408
4453
4409
4454
/*
4410
4455
Implements the with statement from PEP 343.
4411
-
4412
- The semantics outlined in that PEP are as follows:
4413
-
4414
4456
with EXPR as VAR:
4415
4457
BLOCK
4416
-
4417
- It is implemented roughly as:
4418
-
4419
- context = EXPR
4420
- exit = context.__exit__ # not calling it
4421
- value = context.__enter__( )
4422
- try:
4423
- VAR = value # if VAR present in the syntax
4424
- BLOCK
4425
- finally :
4426
- if an exception was raised:
4427
- exc = copy of ( exception, instance, traceback )
4428
- else:
4429
- exc = (None, None, None)
4430
- exit(*exc)
4458
+ is implemented as:
4459
+ <code for EXPR>
4460
+ SETUP_WITH E
4461
+ <code to store to VAR> or POP_TOP
4462
+ <code for BLOCK>
4463
+ LOAD_CONST (None, None, None )
4464
+ CALL_FUNCTION_EX 0
4465
+ JUMP_FORWARD EXIT
4466
+ E: WITH_EXCEPT_START (calls EXPR.__exit__)
4467
+ POP_JUMP_IF_TRUE T :
4468
+ RERAISE
4469
+ T: POP_TOP * 3 (remove exception from stack )
4470
+ POP_EXCEPT
4471
+ POP_TOP
4472
+ EXIT:
4431
4473
*/
4474
+
4432
4475
static int
4433
4476
compiler_with (struct compiler * c , stmt_ty s , int pos )
4434
4477
{
4435
- basicblock * block , * finally ;
4478
+ basicblock * block , * final1 , * final2 , * exit ;
4436
4479
withitem_ty item = asdl_seq_GET (s -> v .With .items , pos );
4437
4480
4438
4481
assert (s -> kind == With_kind );
4439
4482
4440
4483
block = compiler_new_block (c );
4441
- finally = compiler_new_block (c );
4442
- if (!block || !finally )
4484
+ final1 = compiler_new_block (c );
4485
+ final2 = compiler_new_block (c );
4486
+ exit = compiler_new_block (c );
4487
+ if (!block || !final1 || !final2 || !exit )
4443
4488
return 0 ;
4444
4489
4445
4490
/* Evaluate EXPR */
4446
4491
VISIT (c , expr , item -> context_expr );
4447
- ADDOP_JREL (c , SETUP_WITH , finally );
4492
+ /* Will push bound __exit__ */
4493
+ ADDOP_JREL (c , SETUP_WITH , final2 );
4448
4494
4449
- /* SETUP_WITH pushes a finally block. */
4495
+ /* SETUP_ASYNC_WITH pushes a finally block. */
4450
4496
compiler_use_next_block (c , block );
4451
- if (!compiler_push_fblock (c , WITH , block , finally )) {
4497
+ if (!compiler_push_fblock (c , WITH , block , final2 )) {
4452
4498
return 0 ;
4453
4499
}
4454
4500
@@ -4467,24 +4513,33 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
4467
4513
else if (!compiler_with (c , s , pos ))
4468
4514
return 0 ;
4469
4515
4470
- /* End of try block; start the finally block */
4516
+ /* End of try block; start the finally blocks */
4471
4517
ADDOP (c , POP_BLOCK );
4472
- ADDOP (c , BEGIN_FINALLY );
4473
4518
compiler_pop_fblock (c , WITH , block );
4474
4519
4475
- compiler_use_next_block (c , finally );
4476
- if (!compiler_push_fblock (c , FINALLY_END , finally , NULL ))
4520
+ /* `finally` block for successful outcome:
4521
+ * call __exit__(None, None, None)
4522
+ */
4523
+ compiler_use_next_block (c , final1 );
4524
+ if (!compiler_push_fblock (c , FINALLY_END , final1 , NULL ))
4477
4525
return 0 ;
4478
4526
4479
- /* Finally block starts; context.__exit__ is on the stack under
4480
- the exception or return information. Just issue our magic
4481
- opcode. */
4482
- ADDOP (c , WITH_CLEANUP_START );
4483
- ADDOP (c , WITH_CLEANUP_FINISH );
4527
+ if (! compiler_call_exit_with_nones ( c ))
4528
+ return 0 ;
4529
+ ADDOP ( c , POP_TOP );
4530
+ compiler_pop_fblock (c , FINALLY_END , final1 );
4531
+ ADDOP_JREL (c , JUMP_FORWARD , exit );
4484
4532
4485
- /* Finally block ends. */
4486
- ADDOP (c , END_FINALLY );
4487
- compiler_pop_fblock (c , FINALLY_END , finally );
4533
+ /* `finally` block for exceptional outcome */
4534
+ compiler_use_next_block (c , final2 );
4535
+ if (!compiler_push_fblock (c , FINALLY_END , final2 , NULL ))
4536
+ return 0 ;
4537
+
4538
+ ADDOP (c , WITH_EXCEPT_START );
4539
+ compiler_with_except_finish (c );
4540
+ compiler_pop_fblock (c , FINALLY_END , final2 );
4541
+
4542
+ compiler_use_next_block (c , exit );
4488
4543
return 1 ;
4489
4544
}
4490
4545
0 commit comments