@@ -11,6 +11,7 @@ use crate::peephole::PeepholeOptimizer;
11
11
use crate :: symboltable:: {
12
12
make_symbol_table, statements_to_symbol_table, Symbol , SymbolScope , SymbolTable ,
13
13
} ;
14
+ use itertools:: Itertools ;
14
15
use num_complex:: Complex64 ;
15
16
use rustpython_bytecode:: bytecode:: { self , CallType , CodeObject , Instruction , Label , Varargs } ;
16
17
use rustpython_parser:: { ast, parser} ;
@@ -1438,6 +1439,47 @@ impl<O: OutputStream> Compiler<O> {
1438
1439
Ok ( ( ) )
1439
1440
}
1440
1441
1442
+ fn compile_dict (
1443
+ & mut self ,
1444
+ pairs : & [ ( Option < ast:: Expression > , ast:: Expression ) ] ,
1445
+ ) -> Result < ( ) , CompileError > {
1446
+ let mut size = 0 ;
1447
+ let mut has_unpacking = false ;
1448
+ for ( is_unpacking, subpairs) in & pairs. iter ( ) . group_by ( |e| e. 0 . is_none ( ) ) {
1449
+ if is_unpacking {
1450
+ for ( _, value) in subpairs {
1451
+ self . compile_expression ( value) ?;
1452
+ size += 1 ;
1453
+ }
1454
+ has_unpacking = true ;
1455
+ } else {
1456
+ let mut subsize = 0 ;
1457
+ for ( key, value) in subpairs {
1458
+ if let Some ( key) = key {
1459
+ self . compile_expression ( key) ?;
1460
+ self . compile_expression ( value) ?;
1461
+ subsize += 1 ;
1462
+ }
1463
+ }
1464
+ self . emit ( Instruction :: BuildMap {
1465
+ size : subsize,
1466
+ unpack : false ,
1467
+ } ) ;
1468
+ size += 1 ;
1469
+ }
1470
+ }
1471
+ if size == 0 {
1472
+ self . emit ( Instruction :: BuildMap {
1473
+ size,
1474
+ unpack : false ,
1475
+ } ) ;
1476
+ }
1477
+ if size > 1 || has_unpacking {
1478
+ self . emit ( Instruction :: BuildMap { size, unpack : true } ) ;
1479
+ }
1480
+ Ok ( ( ) )
1481
+ }
1482
+
1441
1483
fn compile_expression ( & mut self , expression : & ast:: Expression ) -> Result < ( ) , CompileError > {
1442
1484
trace ! ( "Compiling {:?}" , expression) ;
1443
1485
self . set_source_location ( & expression. location ) ;
@@ -1521,27 +1563,7 @@ impl<O: OutputStream> Compiler<O> {
1521
1563
} ) ;
1522
1564
}
1523
1565
Dict { elements } => {
1524
- let size = elements. len ( ) ;
1525
- let has_double_star = elements. iter ( ) . any ( |e| e. 0 . is_none ( ) ) ;
1526
- for ( key, value) in elements {
1527
- if let Some ( key) = key {
1528
- self . compile_expression ( key) ?;
1529
- self . compile_expression ( value) ?;
1530
- if has_double_star {
1531
- self . emit ( Instruction :: BuildMap {
1532
- size : 1 ,
1533
- unpack : false ,
1534
- } ) ;
1535
- }
1536
- } else {
1537
- // dict unpacking
1538
- self . compile_expression ( value) ?;
1539
- }
1540
- }
1541
- self . emit ( Instruction :: BuildMap {
1542
- size,
1543
- unpack : has_double_star,
1544
- } ) ;
1566
+ self . compile_dict ( elements) ?;
1545
1567
}
1546
1568
Slice { elements } => {
1547
1569
let size = elements. len ( ) ;
@@ -1658,6 +1680,40 @@ impl<O: OutputStream> Compiler<O> {
1658
1680
Ok ( ( ) )
1659
1681
}
1660
1682
1683
+ fn compile_keywords ( & mut self , keywords : & [ ast:: Keyword ] ) -> Result < ( ) , CompileError > {
1684
+ let mut size = 0 ;
1685
+ for ( is_unpacking, subkeywords) in & keywords. iter ( ) . group_by ( |e| e. name . is_none ( ) ) {
1686
+ if is_unpacking {
1687
+ for keyword in subkeywords {
1688
+ self . compile_expression ( & keyword. value ) ?;
1689
+ size += 1 ;
1690
+ }
1691
+ } else {
1692
+ let mut subsize = 0 ;
1693
+ for keyword in subkeywords {
1694
+ if let Some ( name) = & keyword. name {
1695
+ self . emit ( Instruction :: LoadConst {
1696
+ value : bytecode:: Constant :: String {
1697
+ value : name. to_string ( ) ,
1698
+ } ,
1699
+ } ) ;
1700
+ self . compile_expression ( & keyword. value ) ?;
1701
+ subsize += 1 ;
1702
+ }
1703
+ }
1704
+ self . emit ( Instruction :: BuildMap {
1705
+ size : subsize,
1706
+ unpack : false ,
1707
+ } ) ;
1708
+ size += 1 ;
1709
+ }
1710
+ }
1711
+ if size > 1 {
1712
+ self . emit ( Instruction :: BuildMap { size, unpack : true } ) ;
1713
+ }
1714
+ Ok ( ( ) )
1715
+ }
1716
+
1661
1717
fn compile_call (
1662
1718
& mut self ,
1663
1719
function : & ast:: Expression ,
@@ -1680,31 +1736,7 @@ impl<O: OutputStream> Compiler<O> {
1680
1736
1681
1737
// Create an optional map with kw-args:
1682
1738
if !keywords. is_empty ( ) {
1683
- for keyword in keywords {
1684
- if let Some ( name) = & keyword. name {
1685
- self . emit ( Instruction :: LoadConst {
1686
- value : bytecode:: Constant :: String {
1687
- value : name. to_string ( ) ,
1688
- } ,
1689
- } ) ;
1690
- self . compile_expression ( & keyword. value ) ?;
1691
- if has_double_star {
1692
- self . emit ( Instruction :: BuildMap {
1693
- size : 1 ,
1694
- unpack : false ,
1695
- } ) ;
1696
- }
1697
- } else {
1698
- // This means **kwargs!
1699
- self . compile_expression ( & keyword. value ) ?;
1700
- }
1701
- }
1702
-
1703
- self . emit ( Instruction :: BuildMap {
1704
- size : keywords. len ( ) ,
1705
- unpack : has_double_star,
1706
- } ) ;
1707
-
1739
+ self . compile_keywords ( keywords) ?;
1708
1740
self . emit ( Instruction :: CallFunction {
1709
1741
typ : CallType :: Ex ( true ) ,
1710
1742
} ) ;
0 commit comments