rustpython_codegen/
compile.rs

1//!
2//! Take an AST and transform it into bytecode
3//!
4//! Inspirational code:
5//!   <https://github.com/python/cpython/blob/main/Python/compile.c>
6//!   <https://github.com/micropython/micropython/blob/master/py/compile.c>
7
8#![deny(clippy::cast_possible_truncation)]
9
10use crate::{
11    error::{CodegenError, CodegenErrorType},
12    ir,
13    symboltable::{self, SymbolFlags, SymbolScope, SymbolTable},
14    IndexSet,
15};
16use itertools::Itertools;
17use num_complex::Complex64;
18use num_traits::ToPrimitive;
19use rustpython_ast::located::{self as located_ast, Located};
20use rustpython_compiler_core::{
21    bytecode::{self, Arg as OpArgMarker, CodeObject, ConstantData, Instruction, OpArg, OpArgType},
22    Mode,
23};
24use rustpython_parser_core::source_code::{LineNumber, SourceLocation};
25use std::borrow::Cow;
26
27type CompileResult<T> = Result<T, CodegenError>;
28
29#[derive(PartialEq, Eq, Clone, Copy)]
30enum NameUsage {
31    Load,
32    Store,
33    Delete,
34}
35
36enum CallType {
37    Positional { nargs: u32 },
38    Keyword { nargs: u32 },
39    Ex { has_kwargs: bool },
40}
41
42fn is_forbidden_name(name: &str) -> bool {
43    // See https://docs.python.org/3/library/constants.html#built-in-constants
44    const BUILTIN_CONSTANTS: &[&str] = &["__debug__"];
45
46    BUILTIN_CONSTANTS.contains(&name)
47}
48
49/// Main structure holding the state of compilation.
50struct Compiler {
51    code_stack: Vec<ir::CodeInfo>,
52    symbol_table_stack: Vec<SymbolTable>,
53    source_path: String,
54    current_source_location: SourceLocation,
55    qualified_path: Vec<String>,
56    done_with_future_stmts: bool,
57    future_annotations: bool,
58    ctx: CompileContext,
59    class_name: Option<String>,
60    opts: CompileOpts,
61}
62
63#[derive(Debug, Clone, Default)]
64pub struct CompileOpts {
65    /// How optimized the bytecode output should be; any optimize > 0 does
66    /// not emit assert statements
67    pub optimize: u8,
68}
69
70#[derive(Debug, Clone, Copy)]
71struct CompileContext {
72    loop_data: Option<(ir::BlockIdx, ir::BlockIdx)>,
73    in_class: bool,
74    func: FunctionContext,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq)]
78enum FunctionContext {
79    NoFunction,
80    Function,
81    AsyncFunction,
82}
83
84impl CompileContext {
85    fn in_func(self) -> bool {
86        self.func != FunctionContext::NoFunction
87    }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq)]
91enum ComprehensionType {
92    Generator,
93    List,
94    Set,
95    Dict,
96}
97
98/// Compile an located_ast::Mod produced from rustpython_parser::parse()
99pub fn compile_top(
100    ast: &located_ast::Mod,
101    source_path: String,
102    mode: Mode,
103    opts: CompileOpts,
104) -> CompileResult<CodeObject> {
105    match ast {
106        located_ast::Mod::Module(located_ast::ModModule { body, .. }) => {
107            compile_program(body, source_path, opts)
108        }
109        located_ast::Mod::Interactive(located_ast::ModInteractive { body, .. }) => match mode {
110            Mode::Single => compile_program_single(body, source_path, opts),
111            Mode::BlockExpr => compile_block_expression(body, source_path, opts),
112            _ => unreachable!("only Single and BlockExpr parsed to Interactive"),
113        },
114        located_ast::Mod::Expression(located_ast::ModExpression { body, .. }) => {
115            compile_expression(body, source_path, opts)
116        }
117        located_ast::Mod::FunctionType(_) => panic!("can't compile a FunctionType"),
118    }
119}
120
121/// A helper function for the shared code of the different compile functions
122fn compile_impl<Ast: ?Sized>(
123    ast: &Ast,
124    source_path: String,
125    opts: CompileOpts,
126    make_symbol_table: impl FnOnce(&Ast) -> Result<SymbolTable, symboltable::SymbolTableError>,
127    compile: impl FnOnce(&mut Compiler, &Ast, SymbolTable) -> CompileResult<()>,
128) -> CompileResult<CodeObject> {
129    let symbol_table = match make_symbol_table(ast) {
130        Ok(x) => x,
131        Err(e) => return Err(e.into_codegen_error(source_path)),
132    };
133
134    let mut compiler = Compiler::new(opts, source_path, "<module>".to_owned());
135    compile(&mut compiler, ast, symbol_table)?;
136    let code = compiler.pop_code_object();
137    trace!("Compilation completed: {:?}", code);
138    Ok(code)
139}
140
141/// Compile a standard Python program to bytecode
142pub fn compile_program(
143    ast: &[located_ast::Stmt],
144    source_path: String,
145    opts: CompileOpts,
146) -> CompileResult<CodeObject> {
147    compile_impl(
148        ast,
149        source_path,
150        opts,
151        SymbolTable::scan_program,
152        Compiler::compile_program,
153    )
154}
155
156/// Compile a Python program to bytecode for the context of a REPL
157pub fn compile_program_single(
158    ast: &[located_ast::Stmt],
159    source_path: String,
160    opts: CompileOpts,
161) -> CompileResult<CodeObject> {
162    compile_impl(
163        ast,
164        source_path,
165        opts,
166        SymbolTable::scan_program,
167        Compiler::compile_program_single,
168    )
169}
170
171pub fn compile_block_expression(
172    ast: &[located_ast::Stmt],
173    source_path: String,
174    opts: CompileOpts,
175) -> CompileResult<CodeObject> {
176    compile_impl(
177        ast,
178        source_path,
179        opts,
180        SymbolTable::scan_program,
181        Compiler::compile_block_expr,
182    )
183}
184
185pub fn compile_expression(
186    ast: &located_ast::Expr,
187    source_path: String,
188    opts: CompileOpts,
189) -> CompileResult<CodeObject> {
190    compile_impl(
191        ast,
192        source_path,
193        opts,
194        SymbolTable::scan_expr,
195        Compiler::compile_eval,
196    )
197}
198
199macro_rules! emit {
200    ($c:expr, Instruction::$op:ident { $arg:ident$(,)? }$(,)?) => {
201        $c.emit_arg($arg, |x| Instruction::$op { $arg: x })
202    };
203    ($c:expr, Instruction::$op:ident { $arg:ident : $arg_val:expr $(,)? }$(,)?) => {
204        $c.emit_arg($arg_val, |x| Instruction::$op { $arg: x })
205    };
206    ($c:expr, Instruction::$op:ident( $arg_val:expr $(,)? )$(,)?) => {
207        $c.emit_arg($arg_val, Instruction::$op)
208    };
209    ($c:expr, Instruction::$op:ident$(,)?) => {
210        $c.emit_no_arg(Instruction::$op)
211    };
212}
213
214impl Compiler {
215    fn new(opts: CompileOpts, source_path: String, code_name: String) -> Self {
216        let module_code = ir::CodeInfo {
217            flags: bytecode::CodeFlags::NEW_LOCALS,
218            posonlyarg_count: 0,
219            arg_count: 0,
220            kwonlyarg_count: 0,
221            source_path: source_path.clone(),
222            first_line_number: LineNumber::MIN,
223            obj_name: code_name,
224
225            blocks: vec![ir::Block::default()],
226            current_block: ir::BlockIdx(0),
227            constants: IndexSet::default(),
228            name_cache: IndexSet::default(),
229            varname_cache: IndexSet::default(),
230            cellvar_cache: IndexSet::default(),
231            freevar_cache: IndexSet::default(),
232        };
233        Compiler {
234            code_stack: vec![module_code],
235            symbol_table_stack: Vec::new(),
236            source_path,
237            current_source_location: SourceLocation::default(),
238            qualified_path: Vec::new(),
239            done_with_future_stmts: false,
240            future_annotations: false,
241            ctx: CompileContext {
242                loop_data: None,
243                in_class: false,
244                func: FunctionContext::NoFunction,
245            },
246            class_name: None,
247            opts,
248        }
249    }
250
251    fn error(&mut self, error: CodegenErrorType) -> CodegenError {
252        self.error_loc(error, self.current_source_location)
253    }
254    fn error_loc(&mut self, error: CodegenErrorType, location: SourceLocation) -> CodegenError {
255        CodegenError {
256            error,
257            location: Some(location),
258            source_path: self.source_path.clone(),
259        }
260    }
261
262    /// Push the next symbol table on to the stack
263    fn push_symbol_table(&mut self) -> &SymbolTable {
264        // Look up the next table contained in the scope of the current table
265        let table = self
266            .symbol_table_stack
267            .last_mut()
268            .expect("no next symbol table")
269            .sub_tables
270            .remove(0);
271        // Push the next table onto the stack
272        let last_idx = self.symbol_table_stack.len();
273        self.symbol_table_stack.push(table);
274        &self.symbol_table_stack[last_idx]
275    }
276
277    /// Pop the current symbol table off the stack
278    fn pop_symbol_table(&mut self) -> SymbolTable {
279        self.symbol_table_stack.pop().expect("compiler bug")
280    }
281
282    fn push_output(
283        &mut self,
284        flags: bytecode::CodeFlags,
285        posonlyarg_count: u32,
286        arg_count: u32,
287        kwonlyarg_count: u32,
288        obj_name: String,
289    ) {
290        let source_path = self.source_path.clone();
291        let first_line_number = self.get_source_line_number();
292
293        let table = self.push_symbol_table();
294
295        let cellvar_cache = table
296            .symbols
297            .iter()
298            .filter(|(_, s)| s.scope == SymbolScope::Cell)
299            .map(|(var, _)| var.clone())
300            .collect();
301        let freevar_cache = table
302            .symbols
303            .iter()
304            .filter(|(_, s)| {
305                s.scope == SymbolScope::Free || s.flags.contains(SymbolFlags::FREE_CLASS)
306            })
307            .map(|(var, _)| var.clone())
308            .collect();
309
310        let info = ir::CodeInfo {
311            flags,
312            posonlyarg_count,
313            arg_count,
314            kwonlyarg_count,
315            source_path,
316            first_line_number,
317            obj_name,
318
319            blocks: vec![ir::Block::default()],
320            current_block: ir::BlockIdx(0),
321            constants: IndexSet::default(),
322            name_cache: IndexSet::default(),
323            varname_cache: IndexSet::default(),
324            cellvar_cache,
325            freevar_cache,
326        };
327        self.code_stack.push(info);
328    }
329
330    fn pop_code_object(&mut self) -> CodeObject {
331        let table = self.pop_symbol_table();
332        assert!(table.sub_tables.is_empty());
333        self.code_stack
334            .pop()
335            .unwrap()
336            .finalize_code(self.opts.optimize)
337    }
338
339    // could take impl Into<Cow<str>>, but everything is borrowed from ast structs; we never
340    // actually have a `String` to pass
341    fn name(&mut self, name: &str) -> bytecode::NameIdx {
342        self._name_inner(name, |i| &mut i.name_cache)
343    }
344    fn varname(&mut self, name: &str) -> CompileResult<bytecode::NameIdx> {
345        if Compiler::is_forbidden_arg_name(name) {
346            return Err(self.error(CodegenErrorType::SyntaxError(format!(
347                "cannot assign to {name}",
348            ))));
349        }
350        Ok(self._name_inner(name, |i| &mut i.varname_cache))
351    }
352    fn _name_inner(
353        &mut self,
354        name: &str,
355        cache: impl FnOnce(&mut ir::CodeInfo) -> &mut IndexSet<String>,
356    ) -> bytecode::NameIdx {
357        let name = self.mangle(name);
358        let cache = cache(self.current_code_info());
359        cache
360            .get_index_of(name.as_ref())
361            .unwrap_or_else(|| cache.insert_full(name.into_owned()).0)
362            .to_u32()
363    }
364
365    fn compile_program(
366        &mut self,
367        body: &[located_ast::Stmt],
368        symbol_table: SymbolTable,
369    ) -> CompileResult<()> {
370        let size_before = self.code_stack.len();
371        self.symbol_table_stack.push(symbol_table);
372
373        let (doc, statements) = split_doc(body, &self.opts);
374        if let Some(value) = doc {
375            self.emit_load_const(ConstantData::Str { value });
376            let doc = self.name("__doc__");
377            emit!(self, Instruction::StoreGlobal(doc))
378        }
379
380        if Self::find_ann(statements) {
381            emit!(self, Instruction::SetupAnnotation);
382        }
383
384        self.compile_statements(statements)?;
385
386        assert_eq!(self.code_stack.len(), size_before);
387
388        // Emit None at end:
389        self.emit_return_const(ConstantData::None);
390        Ok(())
391    }
392
393    fn compile_program_single(
394        &mut self,
395        body: &[located_ast::Stmt],
396        symbol_table: SymbolTable,
397    ) -> CompileResult<()> {
398        self.symbol_table_stack.push(symbol_table);
399
400        if let Some((last, body)) = body.split_last() {
401            for statement in body {
402                if let located_ast::Stmt::Expr(located_ast::StmtExpr { value, .. }) = &statement {
403                    self.compile_expression(value)?;
404                    emit!(self, Instruction::PrintExpr);
405                } else {
406                    self.compile_statement(statement)?;
407                }
408            }
409
410            if let located_ast::Stmt::Expr(located_ast::StmtExpr { value, .. }) = &last {
411                self.compile_expression(value)?;
412                emit!(self, Instruction::Duplicate);
413                emit!(self, Instruction::PrintExpr);
414            } else {
415                self.compile_statement(last)?;
416                self.emit_load_const(ConstantData::None);
417            }
418        } else {
419            self.emit_load_const(ConstantData::None);
420        };
421
422        self.emit_return_value();
423        Ok(())
424    }
425
426    fn compile_block_expr(
427        &mut self,
428        body: &[located_ast::Stmt],
429        symbol_table: SymbolTable,
430    ) -> CompileResult<()> {
431        self.symbol_table_stack.push(symbol_table);
432
433        self.compile_statements(body)?;
434
435        if let Some(last_statement) = body.last() {
436            match last_statement {
437                located_ast::Stmt::Expr(_) => {
438                    self.current_block().instructions.pop(); // pop Instruction::Pop
439                }
440                located_ast::Stmt::FunctionDef(_)
441                | located_ast::Stmt::AsyncFunctionDef(_)
442                | located_ast::Stmt::ClassDef(_) => {
443                    let store_inst = self.current_block().instructions.pop().unwrap(); // pop Instruction::Store
444                    emit!(self, Instruction::Duplicate);
445                    self.current_block().instructions.push(store_inst);
446                }
447                _ => self.emit_load_const(ConstantData::None),
448            }
449        }
450        self.emit_return_value();
451
452        Ok(())
453    }
454
455    // Compile statement in eval mode:
456    fn compile_eval(
457        &mut self,
458        expression: &located_ast::Expr,
459        symbol_table: SymbolTable,
460    ) -> CompileResult<()> {
461        self.symbol_table_stack.push(symbol_table);
462        self.compile_expression(expression)?;
463        self.emit_return_value();
464        Ok(())
465    }
466
467    fn compile_statements(&mut self, statements: &[located_ast::Stmt]) -> CompileResult<()> {
468        for statement in statements {
469            self.compile_statement(statement)?
470        }
471        Ok(())
472    }
473
474    fn load_name(&mut self, name: &str) -> CompileResult<()> {
475        self.compile_name(name, NameUsage::Load)
476    }
477
478    fn store_name(&mut self, name: &str) -> CompileResult<()> {
479        self.compile_name(name, NameUsage::Store)
480    }
481
482    fn mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
483        symboltable::mangle_name(self.class_name.as_deref(), name)
484    }
485
486    fn check_forbidden_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
487        let msg = match usage {
488            NameUsage::Store if is_forbidden_name(name) => "cannot assign to",
489            NameUsage::Delete if is_forbidden_name(name) => "cannot delete",
490            _ => return Ok(()),
491        };
492        Err(self.error(CodegenErrorType::SyntaxError(format!("{msg} {name}"))))
493    }
494
495    fn compile_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
496        let name = self.mangle(name);
497
498        self.check_forbidden_name(&name, usage)?;
499
500        let symbol_table = self.symbol_table_stack.last().unwrap();
501        let symbol = symbol_table.lookup(name.as_ref()).unwrap_or_else(||
502            panic!("The symbol '{name}' must be present in the symbol table, even when it is undefined in python."),
503        );
504        let info = self.code_stack.last_mut().unwrap();
505        let mut cache = &mut info.name_cache;
506        enum NameOpType {
507            Fast,
508            Global,
509            Deref,
510            Local,
511        }
512        let op_typ = match symbol.scope {
513            SymbolScope::Local if self.ctx.in_func() => {
514                cache = &mut info.varname_cache;
515                NameOpType::Fast
516            }
517            SymbolScope::GlobalExplicit => NameOpType::Global,
518            SymbolScope::GlobalImplicit | SymbolScope::Unknown if self.ctx.in_func() => {
519                NameOpType::Global
520            }
521            SymbolScope::GlobalImplicit | SymbolScope::Unknown => NameOpType::Local,
522            SymbolScope::Local => NameOpType::Local,
523            SymbolScope::Free => {
524                cache = &mut info.freevar_cache;
525                NameOpType::Deref
526            }
527            SymbolScope::Cell => {
528                cache = &mut info.cellvar_cache;
529                NameOpType::Deref
530            } // TODO: is this right?
531              // SymbolScope::Unknown => NameOpType::Global,
532        };
533
534        if NameUsage::Load == usage && name == "__debug__" {
535            self.emit_load_const(ConstantData::Boolean {
536                value: self.opts.optimize == 0,
537            });
538            return Ok(());
539        }
540
541        let mut idx = cache
542            .get_index_of(name.as_ref())
543            .unwrap_or_else(|| cache.insert_full(name.into_owned()).0);
544        if let SymbolScope::Free = symbol.scope {
545            idx += info.cellvar_cache.len();
546        }
547        let op = match op_typ {
548            NameOpType::Fast => match usage {
549                NameUsage::Load => Instruction::LoadFast,
550                NameUsage::Store => Instruction::StoreFast,
551                NameUsage::Delete => Instruction::DeleteFast,
552            },
553            NameOpType::Global => match usage {
554                NameUsage::Load => Instruction::LoadGlobal,
555                NameUsage::Store => Instruction::StoreGlobal,
556                NameUsage::Delete => Instruction::DeleteGlobal,
557            },
558            NameOpType::Deref => match usage {
559                NameUsage::Load if !self.ctx.in_func() && self.ctx.in_class => {
560                    Instruction::LoadClassDeref
561                }
562                NameUsage::Load => Instruction::LoadDeref,
563                NameUsage::Store => Instruction::StoreDeref,
564                NameUsage::Delete => Instruction::DeleteDeref,
565            },
566            NameOpType::Local => match usage {
567                NameUsage::Load => Instruction::LoadNameAny,
568                NameUsage::Store => Instruction::StoreLocal,
569                NameUsage::Delete => Instruction::DeleteLocal,
570            },
571        };
572        self.emit_arg(idx.to_u32(), op);
573
574        Ok(())
575    }
576
577    fn compile_statement(&mut self, statement: &located_ast::Stmt) -> CompileResult<()> {
578        use located_ast::*;
579
580        trace!("Compiling {:?}", statement);
581        self.set_source_location(statement.location());
582
583        match &statement {
584            // we do this here because `from __future__` still executes that `from` statement at runtime,
585            // we still need to compile the ImportFrom down below
586            Stmt::ImportFrom(located_ast::StmtImportFrom { module, names, .. })
587                if module.as_ref().map(|id| id.as_str()) == Some("__future__") =>
588            {
589                self.compile_future_features(names)?
590            }
591            // if we find any other statement, stop accepting future statements
592            _ => self.done_with_future_stmts = true,
593        }
594
595        match &statement {
596            Stmt::Import(StmtImport { names, .. }) => {
597                // import a, b, c as d
598                for name in names {
599                    let name = &name;
600                    self.emit_load_const(ConstantData::Integer {
601                        value: num_traits::Zero::zero(),
602                    });
603                    self.emit_load_const(ConstantData::None);
604                    let idx = self.name(&name.name);
605                    emit!(self, Instruction::ImportName { idx });
606                    if let Some(alias) = &name.asname {
607                        for part in name.name.split('.').skip(1) {
608                            let idx = self.name(part);
609                            emit!(self, Instruction::LoadAttr { idx });
610                        }
611                        self.store_name(alias.as_str())?
612                    } else {
613                        self.store_name(name.name.split('.').next().unwrap())?
614                    }
615                }
616            }
617            Stmt::ImportFrom(StmtImportFrom {
618                level,
619                module,
620                names,
621                ..
622            }) => {
623                let import_star = names.iter().any(|n| &n.name == "*");
624
625                let from_list = if import_star {
626                    if self.ctx.in_func() {
627                        return Err(self.error_loc(
628                            CodegenErrorType::FunctionImportStar,
629                            statement.location(),
630                        ));
631                    }
632                    vec![ConstantData::Str {
633                        value: "*".to_owned(),
634                    }]
635                } else {
636                    names
637                        .iter()
638                        .map(|n| ConstantData::Str {
639                            value: n.name.to_string(),
640                        })
641                        .collect()
642                };
643
644                let module_idx = module.as_ref().map(|s| self.name(s.as_str()));
645
646                // from .... import (*fromlist)
647                self.emit_load_const(ConstantData::Integer {
648                    value: level.as_ref().map_or(0, |level| level.to_u32()).into(),
649                });
650                self.emit_load_const(ConstantData::Tuple {
651                    elements: from_list,
652                });
653                if let Some(idx) = module_idx {
654                    emit!(self, Instruction::ImportName { idx });
655                } else {
656                    emit!(self, Instruction::ImportNameless);
657                }
658
659                if import_star {
660                    // from .... import *
661                    emit!(self, Instruction::ImportStar);
662                } else {
663                    // from mod import a, b as c
664
665                    for name in names {
666                        let name = &name;
667                        let idx = self.name(name.name.as_str());
668                        // import symbol from module:
669                        emit!(self, Instruction::ImportFrom { idx });
670
671                        // Store module under proper name:
672                        if let Some(alias) = &name.asname {
673                            self.store_name(alias.as_str())?
674                        } else {
675                            self.store_name(name.name.as_str())?
676                        }
677                    }
678
679                    // Pop module from stack:
680                    emit!(self, Instruction::Pop);
681                }
682            }
683            Stmt::Expr(StmtExpr { value, .. }) => {
684                self.compile_expression(value)?;
685
686                // Pop result of stack, since we not use it:
687                emit!(self, Instruction::Pop);
688            }
689            Stmt::Global(_) | Stmt::Nonlocal(_) => {
690                // Handled during symbol table construction.
691            }
692            Stmt::If(StmtIf {
693                test, body, orelse, ..
694            }) => {
695                let after_block = self.new_block();
696                if orelse.is_empty() {
697                    // Only if:
698                    self.compile_jump_if(test, false, after_block)?;
699                    self.compile_statements(body)?;
700                } else {
701                    // if - else:
702                    let else_block = self.new_block();
703                    self.compile_jump_if(test, false, else_block)?;
704                    self.compile_statements(body)?;
705                    emit!(
706                        self,
707                        Instruction::Jump {
708                            target: after_block,
709                        }
710                    );
711
712                    // else:
713                    self.switch_to_block(else_block);
714                    self.compile_statements(orelse)?;
715                }
716                self.switch_to_block(after_block);
717            }
718            Stmt::While(StmtWhile {
719                test, body, orelse, ..
720            }) => self.compile_while(test, body, orelse)?,
721            Stmt::With(StmtWith { items, body, .. }) => self.compile_with(items, body, false)?,
722            Stmt::AsyncWith(StmtAsyncWith { items, body, .. }) => {
723                self.compile_with(items, body, true)?
724            }
725            Stmt::For(StmtFor {
726                target,
727                iter,
728                body,
729                orelse,
730                ..
731            }) => self.compile_for(target, iter, body, orelse, false)?,
732            Stmt::AsyncFor(StmtAsyncFor {
733                target,
734                iter,
735                body,
736                orelse,
737                ..
738            }) => self.compile_for(target, iter, body, orelse, true)?,
739            Stmt::Match(StmtMatch { subject, cases, .. }) => self.compile_match(subject, cases)?,
740            Stmt::Raise(StmtRaise { exc, cause, .. }) => {
741                let kind = match exc {
742                    Some(value) => {
743                        self.compile_expression(value)?;
744                        match cause {
745                            Some(cause) => {
746                                self.compile_expression(cause)?;
747                                bytecode::RaiseKind::RaiseCause
748                            }
749                            None => bytecode::RaiseKind::Raise,
750                        }
751                    }
752                    None => bytecode::RaiseKind::Reraise,
753                };
754                emit!(self, Instruction::Raise { kind });
755            }
756            Stmt::Try(StmtTry {
757                body,
758                handlers,
759                orelse,
760                finalbody,
761                ..
762            }) => self.compile_try_statement(body, handlers, orelse, finalbody)?,
763            Stmt::TryStar(StmtTryStar {
764                body,
765                handlers,
766                orelse,
767                finalbody,
768                ..
769            }) => self.compile_try_star_statement(body, handlers, orelse, finalbody)?,
770            Stmt::FunctionDef(StmtFunctionDef {
771                name,
772                args,
773                body,
774                decorator_list,
775                returns,
776                type_params,
777                ..
778            }) => self.compile_function_def(
779                name.as_str(),
780                args,
781                body,
782                decorator_list,
783                returns.as_deref(),
784                false,
785                type_params,
786            )?,
787            Stmt::AsyncFunctionDef(StmtAsyncFunctionDef {
788                name,
789                args,
790                body,
791                decorator_list,
792                returns,
793                type_params,
794                ..
795            }) => self.compile_function_def(
796                name.as_str(),
797                args,
798                body,
799                decorator_list,
800                returns.as_deref(),
801                true,
802                type_params,
803            )?,
804            Stmt::ClassDef(StmtClassDef {
805                name,
806                body,
807                bases,
808                keywords,
809                decorator_list,
810                type_params,
811                ..
812            }) => self.compile_class_def(
813                name.as_str(),
814                body,
815                bases,
816                keywords,
817                decorator_list,
818                type_params,
819            )?,
820            Stmt::Assert(StmtAssert { test, msg, .. }) => {
821                // if some flag, ignore all assert statements!
822                if self.opts.optimize == 0 {
823                    let after_block = self.new_block();
824                    self.compile_jump_if(test, true, after_block)?;
825
826                    let assertion_error = self.name("AssertionError");
827                    emit!(self, Instruction::LoadGlobal(assertion_error));
828                    match msg {
829                        Some(e) => {
830                            self.compile_expression(e)?;
831                            emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
832                        }
833                        None => {
834                            emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
835                        }
836                    }
837                    emit!(
838                        self,
839                        Instruction::Raise {
840                            kind: bytecode::RaiseKind::Raise,
841                        }
842                    );
843
844                    self.switch_to_block(after_block);
845                }
846            }
847            Stmt::Break(_) => match self.ctx.loop_data {
848                Some((_, end)) => {
849                    emit!(self, Instruction::Break { target: end });
850                }
851                None => {
852                    return Err(
853                        self.error_loc(CodegenErrorType::InvalidBreak, statement.location())
854                    );
855                }
856            },
857            Stmt::Continue(_) => match self.ctx.loop_data {
858                Some((start, _)) => {
859                    emit!(self, Instruction::Continue { target: start });
860                }
861                None => {
862                    return Err(
863                        self.error_loc(CodegenErrorType::InvalidContinue, statement.location())
864                    );
865                }
866            },
867            Stmt::Return(StmtReturn { value, .. }) => {
868                if !self.ctx.in_func() {
869                    return Err(
870                        self.error_loc(CodegenErrorType::InvalidReturn, statement.location())
871                    );
872                }
873                match value {
874                    Some(v) => {
875                        if self.ctx.func == FunctionContext::AsyncFunction
876                            && self
877                                .current_code_info()
878                                .flags
879                                .contains(bytecode::CodeFlags::IS_GENERATOR)
880                        {
881                            return Err(self.error_loc(
882                                CodegenErrorType::AsyncReturnValue,
883                                statement.location(),
884                            ));
885                        }
886                        self.compile_expression(v)?;
887                        self.emit_return_value();
888                    }
889                    None => {
890                        self.emit_return_const(ConstantData::None);
891                    }
892                }
893            }
894            Stmt::Assign(StmtAssign { targets, value, .. }) => {
895                self.compile_expression(value)?;
896
897                for (i, target) in targets.iter().enumerate() {
898                    if i + 1 != targets.len() {
899                        emit!(self, Instruction::Duplicate);
900                    }
901                    self.compile_store(target)?;
902                }
903            }
904            Stmt::AugAssign(StmtAugAssign {
905                target, op, value, ..
906            }) => self.compile_augassign(target, op, value)?,
907            Stmt::AnnAssign(StmtAnnAssign {
908                target,
909                annotation,
910                value,
911                ..
912            }) => self.compile_annotated_assign(target, annotation, value.as_deref())?,
913            Stmt::Delete(StmtDelete { targets, .. }) => {
914                for target in targets {
915                    self.compile_delete(target)?;
916                }
917            }
918            Stmt::Pass(_) => {
919                // No need to emit any code here :)
920            }
921            Stmt::TypeAlias(StmtTypeAlias {
922                name,
923                type_params,
924                value,
925                ..
926            }) => {
927                let name_string = name.to_string();
928                if !type_params.is_empty() {
929                    self.push_symbol_table();
930                }
931                self.compile_expression(value)?;
932                self.compile_type_params(type_params)?;
933                if !type_params.is_empty() {
934                    self.pop_symbol_table();
935                }
936                self.emit_load_const(ConstantData::Str {
937                    value: name_string.clone(),
938                });
939                emit!(self, Instruction::TypeAlias);
940                self.store_name(&name_string)?;
941            }
942        }
943        Ok(())
944    }
945
946    fn compile_delete(&mut self, expression: &located_ast::Expr) -> CompileResult<()> {
947        match &expression {
948            located_ast::Expr::Name(located_ast::ExprName { id, .. }) => {
949                self.compile_name(id.as_str(), NameUsage::Delete)?
950            }
951            located_ast::Expr::Attribute(located_ast::ExprAttribute { value, attr, .. }) => {
952                self.check_forbidden_name(attr.as_str(), NameUsage::Delete)?;
953                self.compile_expression(value)?;
954                let idx = self.name(attr.as_str());
955                emit!(self, Instruction::DeleteAttr { idx });
956            }
957            located_ast::Expr::Subscript(located_ast::ExprSubscript { value, slice, .. }) => {
958                self.compile_expression(value)?;
959                self.compile_expression(slice)?;
960                emit!(self, Instruction::DeleteSubscript);
961            }
962            located_ast::Expr::Tuple(located_ast::ExprTuple { elts, .. })
963            | located_ast::Expr::List(located_ast::ExprList { elts, .. }) => {
964                for element in elts {
965                    self.compile_delete(element)?;
966                }
967            }
968            located_ast::Expr::BinOp(_) | located_ast::Expr::UnaryOp(_) => {
969                return Err(self.error(CodegenErrorType::Delete("expression")))
970            }
971            _ => return Err(self.error(CodegenErrorType::Delete(expression.python_name()))),
972        }
973        Ok(())
974    }
975
976    fn enter_function(
977        &mut self,
978        name: &str,
979        args: &located_ast::Arguments,
980    ) -> CompileResult<bytecode::MakeFunctionFlags> {
981        let defaults: Vec<_> = args.defaults().collect();
982        let have_defaults = !defaults.is_empty();
983        if have_defaults {
984            // Construct a tuple:
985            let size = defaults.len().to_u32();
986            for element in &defaults {
987                self.compile_expression(element)?;
988            }
989            emit!(self, Instruction::BuildTuple { size });
990        }
991
992        let (kw_without_defaults, kw_with_defaults) = args.split_kwonlyargs();
993        if !kw_with_defaults.is_empty() {
994            let default_kw_count = kw_with_defaults.len();
995            for (arg, default) in kw_with_defaults.iter() {
996                self.emit_load_const(ConstantData::Str {
997                    value: arg.arg.to_string(),
998                });
999                self.compile_expression(default)?;
1000            }
1001            emit!(
1002                self,
1003                Instruction::BuildMap {
1004                    size: default_kw_count.to_u32(),
1005                }
1006            );
1007        }
1008
1009        let mut func_flags = bytecode::MakeFunctionFlags::empty();
1010        if have_defaults {
1011            func_flags |= bytecode::MakeFunctionFlags::DEFAULTS;
1012        }
1013        if !kw_with_defaults.is_empty() {
1014            func_flags |= bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS;
1015        }
1016
1017        self.push_output(
1018            bytecode::CodeFlags::NEW_LOCALS | bytecode::CodeFlags::IS_OPTIMIZED,
1019            args.posonlyargs.len().to_u32(),
1020            (args.posonlyargs.len() + args.args.len()).to_u32(),
1021            args.kwonlyargs.len().to_u32(),
1022            name.to_owned(),
1023        );
1024
1025        let args_iter = std::iter::empty()
1026            .chain(&args.posonlyargs)
1027            .chain(&args.args)
1028            .map(|arg| arg.as_arg())
1029            .chain(kw_without_defaults)
1030            .chain(kw_with_defaults.into_iter().map(|(arg, _)| arg));
1031        for name in args_iter {
1032            self.varname(name.arg.as_str())?;
1033        }
1034
1035        if let Some(name) = args.vararg.as_deref() {
1036            self.current_code_info().flags |= bytecode::CodeFlags::HAS_VARARGS;
1037            self.varname(name.arg.as_str())?;
1038        }
1039        if let Some(name) = args.kwarg.as_deref() {
1040            self.current_code_info().flags |= bytecode::CodeFlags::HAS_VARKEYWORDS;
1041            self.varname(name.arg.as_str())?;
1042        }
1043
1044        Ok(func_flags)
1045    }
1046
1047    fn prepare_decorators(&mut self, decorator_list: &[located_ast::Expr]) -> CompileResult<()> {
1048        for decorator in decorator_list {
1049            self.compile_expression(decorator)?;
1050        }
1051        Ok(())
1052    }
1053
1054    fn apply_decorators(&mut self, decorator_list: &[located_ast::Expr]) {
1055        // Apply decorators:
1056        for _ in decorator_list {
1057            emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
1058        }
1059    }
1060
1061    /// Store each type parameter so it is accessible to the current scope, and leave a tuple of
1062    /// all the type parameters on the stack.
1063    fn compile_type_params(&mut self, type_params: &[located_ast::TypeParam]) -> CompileResult<()> {
1064        for type_param in type_params {
1065            match type_param {
1066                located_ast::TypeParam::TypeVar(located_ast::TypeParamTypeVar {
1067                    name,
1068                    bound,
1069                    ..
1070                }) => {
1071                    if let Some(expr) = &bound {
1072                        self.compile_expression(expr)?;
1073                        self.emit_load_const(ConstantData::Str {
1074                            value: name.to_string(),
1075                        });
1076                        emit!(self, Instruction::TypeVarWithBound);
1077                        emit!(self, Instruction::Duplicate);
1078                        self.store_name(name.as_ref())?;
1079                    } else {
1080                        // self.store_name(type_name.as_str())?;
1081                        self.emit_load_const(ConstantData::Str {
1082                            value: name.to_string(),
1083                        });
1084                        emit!(self, Instruction::TypeVar);
1085                        emit!(self, Instruction::Duplicate);
1086                        self.store_name(name.as_ref())?;
1087                    }
1088                }
1089                located_ast::TypeParam::ParamSpec(_) => todo!(),
1090                located_ast::TypeParam::TypeVarTuple(_) => todo!(),
1091            };
1092        }
1093        emit!(
1094            self,
1095            Instruction::BuildTuple {
1096                size: u32::try_from(type_params.len()).unwrap(),
1097            }
1098        );
1099        Ok(())
1100    }
1101
1102    fn compile_try_statement(
1103        &mut self,
1104        body: &[located_ast::Stmt],
1105        handlers: &[located_ast::ExceptHandler],
1106        orelse: &[located_ast::Stmt],
1107        finalbody: &[located_ast::Stmt],
1108    ) -> CompileResult<()> {
1109        let handler_block = self.new_block();
1110        let finally_block = self.new_block();
1111
1112        // Setup a finally block if we have a finally statement.
1113        if !finalbody.is_empty() {
1114            emit!(
1115                self,
1116                Instruction::SetupFinally {
1117                    handler: finally_block,
1118                }
1119            );
1120        }
1121
1122        let else_block = self.new_block();
1123
1124        // try:
1125        emit!(
1126            self,
1127            Instruction::SetupExcept {
1128                handler: handler_block,
1129            }
1130        );
1131        self.compile_statements(body)?;
1132        emit!(self, Instruction::PopBlock);
1133        emit!(self, Instruction::Jump { target: else_block });
1134
1135        // except handlers:
1136        self.switch_to_block(handler_block);
1137        // Exception is on top of stack now
1138        for handler in handlers {
1139            let located_ast::ExceptHandler::ExceptHandler(
1140                located_ast::ExceptHandlerExceptHandler {
1141                    type_, name, body, ..
1142                },
1143            ) = &handler;
1144            let next_handler = self.new_block();
1145
1146            // If we gave a typ,
1147            // check if this handler can handle the exception:
1148            if let Some(exc_type) = type_ {
1149                // Duplicate exception for test:
1150                emit!(self, Instruction::Duplicate);
1151
1152                // Check exception type:
1153                self.compile_expression(exc_type)?;
1154                emit!(
1155                    self,
1156                    Instruction::TestOperation {
1157                        op: bytecode::TestOperator::ExceptionMatch,
1158                    }
1159                );
1160
1161                // We cannot handle this exception type:
1162                emit!(
1163                    self,
1164                    Instruction::JumpIfFalse {
1165                        target: next_handler,
1166                    }
1167                );
1168
1169                // We have a match, store in name (except x as y)
1170                if let Some(alias) = name {
1171                    self.store_name(alias.as_str())?
1172                } else {
1173                    // Drop exception from top of stack:
1174                    emit!(self, Instruction::Pop);
1175                }
1176            } else {
1177                // Catch all!
1178                // Drop exception from top of stack:
1179                emit!(self, Instruction::Pop);
1180            }
1181
1182            // Handler code:
1183            self.compile_statements(body)?;
1184            emit!(self, Instruction::PopException);
1185
1186            if !finalbody.is_empty() {
1187                emit!(self, Instruction::PopBlock); // pop excepthandler block
1188                                                    // We enter the finally block, without exception.
1189                emit!(self, Instruction::EnterFinally);
1190            }
1191
1192            emit!(
1193                self,
1194                Instruction::Jump {
1195                    target: finally_block,
1196                }
1197            );
1198
1199            // Emit a new label for the next handler
1200            self.switch_to_block(next_handler);
1201        }
1202
1203        // If code flows here, we have an unhandled exception,
1204        // raise the exception again!
1205        emit!(
1206            self,
1207            Instruction::Raise {
1208                kind: bytecode::RaiseKind::Reraise,
1209            }
1210        );
1211
1212        // We successfully ran the try block:
1213        // else:
1214        self.switch_to_block(else_block);
1215        self.compile_statements(orelse)?;
1216
1217        if !finalbody.is_empty() {
1218            emit!(self, Instruction::PopBlock); // pop finally block
1219
1220            // We enter the finallyhandler block, without return / exception.
1221            emit!(self, Instruction::EnterFinally);
1222        }
1223
1224        // finally:
1225        self.switch_to_block(finally_block);
1226        if !finalbody.is_empty() {
1227            self.compile_statements(finalbody)?;
1228            emit!(self, Instruction::EndFinally);
1229        }
1230
1231        Ok(())
1232    }
1233
1234    fn compile_try_star_statement(
1235        &mut self,
1236        _body: &[located_ast::Stmt],
1237        _handlers: &[located_ast::ExceptHandler],
1238        _orelse: &[located_ast::Stmt],
1239        _finalbody: &[located_ast::Stmt],
1240    ) -> CompileResult<()> {
1241        Err(self.error(CodegenErrorType::NotImplementedYet))
1242    }
1243
1244    fn is_forbidden_arg_name(name: &str) -> bool {
1245        is_forbidden_name(name)
1246    }
1247
1248    #[allow(clippy::too_many_arguments)]
1249    fn compile_function_def(
1250        &mut self,
1251        name: &str,
1252        args: &located_ast::Arguments,
1253        body: &[located_ast::Stmt],
1254        decorator_list: &[located_ast::Expr],
1255        returns: Option<&located_ast::Expr>, // TODO: use type hint somehow..
1256        is_async: bool,
1257        type_params: &[located_ast::TypeParam],
1258    ) -> CompileResult<()> {
1259        self.prepare_decorators(decorator_list)?;
1260
1261        // If there are type params, we need to push a special symbol table just for them
1262        if !type_params.is_empty() {
1263            self.push_symbol_table();
1264        }
1265
1266        let mut func_flags = self.enter_function(name, args)?;
1267        self.current_code_info()
1268            .flags
1269            .set(bytecode::CodeFlags::IS_COROUTINE, is_async);
1270
1271        // remember to restore self.ctx.in_loop to the original after the function is compiled
1272        let prev_ctx = self.ctx;
1273
1274        self.ctx = CompileContext {
1275            loop_data: None,
1276            in_class: prev_ctx.in_class,
1277            func: if is_async {
1278                FunctionContext::AsyncFunction
1279            } else {
1280                FunctionContext::Function
1281            },
1282        };
1283
1284        self.push_qualified_path(name);
1285        let qualified_name = self.qualified_path.join(".");
1286        self.push_qualified_path("<locals>");
1287
1288        let (doc_str, body) = split_doc(body, &self.opts);
1289
1290        self.current_code_info()
1291            .constants
1292            .insert_full(ConstantData::None);
1293
1294        self.compile_statements(body)?;
1295
1296        // Emit None at end:
1297        match body.last() {
1298            Some(located_ast::Stmt::Return(_)) => {
1299                // the last instruction is a ReturnValue already, we don't need to emit it
1300            }
1301            _ => {
1302                self.emit_return_const(ConstantData::None);
1303            }
1304        }
1305
1306        let code = self.pop_code_object();
1307        self.qualified_path.pop();
1308        self.qualified_path.pop();
1309        self.ctx = prev_ctx;
1310
1311        // Prepare generic type parameters:
1312        if !type_params.is_empty() {
1313            self.compile_type_params(type_params)?;
1314            func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
1315        }
1316
1317        // Prepare type annotations:
1318        let mut num_annotations = 0;
1319
1320        // Return annotation:
1321        if let Some(annotation) = returns {
1322            // key:
1323            self.emit_load_const(ConstantData::Str {
1324                value: "return".to_owned(),
1325            });
1326            // value:
1327            self.compile_annotation(annotation)?;
1328            num_annotations += 1;
1329        }
1330
1331        let args_iter = std::iter::empty()
1332            .chain(&args.posonlyargs)
1333            .chain(&args.args)
1334            .chain(&args.kwonlyargs)
1335            .map(|arg| arg.as_arg())
1336            .chain(args.vararg.as_deref())
1337            .chain(args.kwarg.as_deref());
1338        for arg in args_iter {
1339            if let Some(annotation) = &arg.annotation {
1340                self.emit_load_const(ConstantData::Str {
1341                    value: self.mangle(arg.arg.as_str()).into_owned(),
1342                });
1343                self.compile_annotation(annotation)?;
1344                num_annotations += 1;
1345            }
1346        }
1347
1348        if num_annotations > 0 {
1349            func_flags |= bytecode::MakeFunctionFlags::ANNOTATIONS;
1350            emit!(
1351                self,
1352                Instruction::BuildMap {
1353                    size: num_annotations,
1354                }
1355            );
1356        }
1357
1358        if self.build_closure(&code) {
1359            func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
1360        }
1361
1362        // Pop the special type params symbol table
1363        if !type_params.is_empty() {
1364            self.pop_symbol_table();
1365        }
1366
1367        self.emit_load_const(ConstantData::Code {
1368            code: Box::new(code),
1369        });
1370        self.emit_load_const(ConstantData::Str {
1371            value: qualified_name,
1372        });
1373
1374        // Turn code object into function object:
1375        emit!(self, Instruction::MakeFunction(func_flags));
1376
1377        if let Some(value) = doc_str {
1378            emit!(self, Instruction::Duplicate);
1379            self.emit_load_const(ConstantData::Str { value });
1380            emit!(self, Instruction::Rotate2);
1381            let doc = self.name("__doc__");
1382            emit!(self, Instruction::StoreAttr { idx: doc });
1383        }
1384
1385        self.apply_decorators(decorator_list);
1386
1387        self.store_name(name)
1388    }
1389
1390    fn build_closure(&mut self, code: &CodeObject) -> bool {
1391        if code.freevars.is_empty() {
1392            return false;
1393        }
1394        for var in &*code.freevars {
1395            let table = self.symbol_table_stack.last().unwrap();
1396            let symbol = table.lookup(var).unwrap_or_else(|| {
1397                panic!(
1398                    "couldn't look up var {} in {} in {}",
1399                    var, code.obj_name, self.source_path
1400                )
1401            });
1402            let parent_code = self.code_stack.last().unwrap();
1403            let vars = match symbol.scope {
1404                SymbolScope::Free => &parent_code.freevar_cache,
1405                SymbolScope::Cell => &parent_code.cellvar_cache,
1406                _ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => &parent_code.freevar_cache,
1407                x => unreachable!(
1408                    "var {} in a {:?} should be free or cell but it's {:?}",
1409                    var, table.typ, x
1410                ),
1411            };
1412            let mut idx = vars.get_index_of(var).unwrap();
1413            if let SymbolScope::Free = symbol.scope {
1414                idx += parent_code.cellvar_cache.len();
1415            }
1416            emit!(self, Instruction::LoadClosure(idx.to_u32()))
1417        }
1418        emit!(
1419            self,
1420            Instruction::BuildTuple {
1421                size: code.freevars.len().to_u32(),
1422            }
1423        );
1424        true
1425    }
1426
1427    // Python/compile.c find_ann
1428    fn find_ann(body: &[located_ast::Stmt]) -> bool {
1429        use located_ast::*;
1430
1431        for statement in body {
1432            let res = match &statement {
1433                Stmt::AnnAssign(_) => true,
1434                Stmt::For(StmtFor { body, orelse, .. }) => {
1435                    Self::find_ann(body) || Self::find_ann(orelse)
1436                }
1437                Stmt::If(StmtIf { body, orelse, .. }) => {
1438                    Self::find_ann(body) || Self::find_ann(orelse)
1439                }
1440                Stmt::While(StmtWhile { body, orelse, .. }) => {
1441                    Self::find_ann(body) || Self::find_ann(orelse)
1442                }
1443                Stmt::With(StmtWith { body, .. }) => Self::find_ann(body),
1444                Stmt::Try(StmtTry {
1445                    body,
1446                    orelse,
1447                    finalbody,
1448                    ..
1449                }) => Self::find_ann(body) || Self::find_ann(orelse) || Self::find_ann(finalbody),
1450                _ => false,
1451            };
1452            if res {
1453                return true;
1454            }
1455        }
1456        false
1457    }
1458
1459    fn compile_class_def(
1460        &mut self,
1461        name: &str,
1462        body: &[located_ast::Stmt],
1463        bases: &[located_ast::Expr],
1464        keywords: &[located_ast::Keyword],
1465        decorator_list: &[located_ast::Expr],
1466        type_params: &[located_ast::TypeParam],
1467    ) -> CompileResult<()> {
1468        self.prepare_decorators(decorator_list)?;
1469
1470        emit!(self, Instruction::LoadBuildClass);
1471
1472        let prev_ctx = self.ctx;
1473        self.ctx = CompileContext {
1474            func: FunctionContext::NoFunction,
1475            in_class: true,
1476            loop_data: None,
1477        };
1478
1479        let prev_class_name = std::mem::replace(&mut self.class_name, Some(name.to_owned()));
1480
1481        // Check if the class is declared global
1482        let symbol_table = self.symbol_table_stack.last().unwrap();
1483        let symbol = symbol_table.lookup(name.as_ref()).expect(
1484            "The symbol must be present in the symbol table, even when it is undefined in python.",
1485        );
1486        let mut global_path_prefix = Vec::new();
1487        if symbol.scope == SymbolScope::GlobalExplicit {
1488            global_path_prefix.append(&mut self.qualified_path);
1489        }
1490        self.push_qualified_path(name);
1491        let qualified_name = self.qualified_path.join(".");
1492
1493        // If there are type params, we need to push a special symbol table just for them
1494        if !type_params.is_empty() {
1495            self.push_symbol_table();
1496        }
1497
1498        self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
1499
1500        let (doc_str, body) = split_doc(body, &self.opts);
1501
1502        let dunder_name = self.name("__name__");
1503        emit!(self, Instruction::LoadGlobal(dunder_name));
1504        let dunder_module = self.name("__module__");
1505        emit!(self, Instruction::StoreLocal(dunder_module));
1506        self.emit_load_const(ConstantData::Str {
1507            value: qualified_name,
1508        });
1509        let qualname = self.name("__qualname__");
1510        emit!(self, Instruction::StoreLocal(qualname));
1511        self.load_docstring(doc_str);
1512        let doc = self.name("__doc__");
1513        emit!(self, Instruction::StoreLocal(doc));
1514        // setup annotations
1515        if Self::find_ann(body) {
1516            emit!(self, Instruction::SetupAnnotation);
1517        }
1518        self.compile_statements(body)?;
1519
1520        let classcell_idx = self
1521            .code_stack
1522            .last_mut()
1523            .unwrap()
1524            .cellvar_cache
1525            .iter()
1526            .position(|var| *var == "__class__");
1527
1528        if let Some(classcell_idx) = classcell_idx {
1529            emit!(self, Instruction::LoadClosure(classcell_idx.to_u32()));
1530            emit!(self, Instruction::Duplicate);
1531            let classcell = self.name("__classcell__");
1532            emit!(self, Instruction::StoreLocal(classcell));
1533        } else {
1534            self.emit_load_const(ConstantData::None);
1535        }
1536
1537        self.emit_return_value();
1538
1539        let code = self.pop_code_object();
1540
1541        self.class_name = prev_class_name;
1542        self.qualified_path.pop();
1543        self.qualified_path.append(global_path_prefix.as_mut());
1544        self.ctx = prev_ctx;
1545
1546        let mut func_flags = bytecode::MakeFunctionFlags::empty();
1547
1548        // Prepare generic type parameters:
1549        if !type_params.is_empty() {
1550            self.compile_type_params(type_params)?;
1551            func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
1552        }
1553
1554        if self.build_closure(&code) {
1555            func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
1556        }
1557
1558        // Pop the special type params symbol table
1559        if !type_params.is_empty() {
1560            self.pop_symbol_table();
1561        }
1562
1563        self.emit_load_const(ConstantData::Code {
1564            code: Box::new(code),
1565        });
1566        self.emit_load_const(ConstantData::Str {
1567            value: name.to_owned(),
1568        });
1569
1570        // Turn code object into function object:
1571        emit!(self, Instruction::MakeFunction(func_flags));
1572
1573        self.emit_load_const(ConstantData::Str {
1574            value: name.to_owned(),
1575        });
1576
1577        let call = self.compile_call_inner(2, bases, keywords)?;
1578        self.compile_normal_call(call);
1579
1580        self.apply_decorators(decorator_list);
1581
1582        self.store_name(name)
1583    }
1584
1585    fn load_docstring(&mut self, doc_str: Option<String>) {
1586        // TODO: __doc__ must be default None and no bytecode unless it is Some
1587        // Duplicate top of stack (the function or class object)
1588
1589        // Doc string value:
1590        self.emit_load_const(match doc_str {
1591            Some(doc) => ConstantData::Str { value: doc },
1592            None => ConstantData::None, // set docstring None if not declared
1593        });
1594    }
1595
1596    fn compile_while(
1597        &mut self,
1598        test: &located_ast::Expr,
1599        body: &[located_ast::Stmt],
1600        orelse: &[located_ast::Stmt],
1601    ) -> CompileResult<()> {
1602        let while_block = self.new_block();
1603        let else_block = self.new_block();
1604        let after_block = self.new_block();
1605
1606        emit!(self, Instruction::SetupLoop);
1607        self.switch_to_block(while_block);
1608
1609        self.compile_jump_if(test, false, else_block)?;
1610
1611        let was_in_loop = self.ctx.loop_data.replace((while_block, after_block));
1612        self.compile_statements(body)?;
1613        self.ctx.loop_data = was_in_loop;
1614        emit!(
1615            self,
1616            Instruction::Jump {
1617                target: while_block,
1618            }
1619        );
1620        self.switch_to_block(else_block);
1621        emit!(self, Instruction::PopBlock);
1622        self.compile_statements(orelse)?;
1623        self.switch_to_block(after_block);
1624        Ok(())
1625    }
1626
1627    fn compile_with(
1628        &mut self,
1629        items: &[located_ast::WithItem],
1630        body: &[located_ast::Stmt],
1631        is_async: bool,
1632    ) -> CompileResult<()> {
1633        let with_location = self.current_source_location;
1634
1635        let Some((item, items)) = items.split_first() else {
1636            return Err(self.error(CodegenErrorType::EmptyWithItems));
1637        };
1638
1639        let final_block = {
1640            let final_block = self.new_block();
1641            self.compile_expression(&item.context_expr)?;
1642
1643            self.set_source_location(with_location);
1644            if is_async {
1645                emit!(self, Instruction::BeforeAsyncWith);
1646                emit!(self, Instruction::GetAwaitable);
1647                self.emit_load_const(ConstantData::None);
1648                emit!(self, Instruction::YieldFrom);
1649                emit!(self, Instruction::SetupAsyncWith { end: final_block });
1650            } else {
1651                emit!(self, Instruction::SetupWith { end: final_block });
1652            }
1653
1654            match &item.optional_vars {
1655                Some(var) => {
1656                    self.set_source_location(var.location());
1657                    self.compile_store(var)?;
1658                }
1659                None => {
1660                    emit!(self, Instruction::Pop);
1661                }
1662            }
1663            final_block
1664        };
1665
1666        if items.is_empty() {
1667            if body.is_empty() {
1668                return Err(self.error(CodegenErrorType::EmptyWithBody));
1669            }
1670            self.compile_statements(body)?;
1671        } else {
1672            self.set_source_location(with_location);
1673            self.compile_with(items, body, is_async)?;
1674        }
1675
1676        // sort of "stack up" the layers of with blocks:
1677        // with a, b: body -> start_with(a) start_with(b) body() end_with(b) end_with(a)
1678        self.set_source_location(with_location);
1679        emit!(self, Instruction::PopBlock);
1680
1681        emit!(self, Instruction::EnterFinally);
1682
1683        self.switch_to_block(final_block);
1684        emit!(self, Instruction::WithCleanupStart);
1685
1686        if is_async {
1687            emit!(self, Instruction::GetAwaitable);
1688            self.emit_load_const(ConstantData::None);
1689            emit!(self, Instruction::YieldFrom);
1690        }
1691
1692        emit!(self, Instruction::WithCleanupFinish);
1693
1694        Ok(())
1695    }
1696
1697    fn compile_for(
1698        &mut self,
1699        target: &located_ast::Expr,
1700        iter: &located_ast::Expr,
1701        body: &[located_ast::Stmt],
1702        orelse: &[located_ast::Stmt],
1703        is_async: bool,
1704    ) -> CompileResult<()> {
1705        // Start loop
1706        let for_block = self.new_block();
1707        let else_block = self.new_block();
1708        let after_block = self.new_block();
1709
1710        emit!(self, Instruction::SetupLoop);
1711
1712        // The thing iterated:
1713        self.compile_expression(iter)?;
1714
1715        if is_async {
1716            emit!(self, Instruction::GetAIter);
1717
1718            self.switch_to_block(for_block);
1719            emit!(
1720                self,
1721                Instruction::SetupExcept {
1722                    handler: else_block,
1723                }
1724            );
1725            emit!(self, Instruction::GetANext);
1726            self.emit_load_const(ConstantData::None);
1727            emit!(self, Instruction::YieldFrom);
1728            self.compile_store(target)?;
1729            emit!(self, Instruction::PopBlock);
1730        } else {
1731            // Retrieve Iterator
1732            emit!(self, Instruction::GetIter);
1733
1734            self.switch_to_block(for_block);
1735            emit!(self, Instruction::ForIter { target: else_block });
1736
1737            // Start of loop iteration, set targets:
1738            self.compile_store(target)?;
1739        };
1740
1741        let was_in_loop = self.ctx.loop_data.replace((for_block, after_block));
1742        self.compile_statements(body)?;
1743        self.ctx.loop_data = was_in_loop;
1744        emit!(self, Instruction::Jump { target: for_block });
1745
1746        self.switch_to_block(else_block);
1747        if is_async {
1748            emit!(self, Instruction::EndAsyncFor);
1749        }
1750        emit!(self, Instruction::PopBlock);
1751        self.compile_statements(orelse)?;
1752
1753        self.switch_to_block(after_block);
1754
1755        Ok(())
1756    }
1757
1758    fn compile_match(
1759        &mut self,
1760        subject: &located_ast::Expr,
1761        cases: &[located_ast::MatchCase],
1762    ) -> CompileResult<()> {
1763        eprintln!("match subject: {subject:?}");
1764        eprintln!("match cases: {cases:?}");
1765        Err(self.error(CodegenErrorType::NotImplementedYet))
1766    }
1767
1768    fn compile_chained_comparison(
1769        &mut self,
1770        left: &located_ast::Expr,
1771        ops: &[located_ast::CmpOp],
1772        exprs: &[located_ast::Expr],
1773    ) -> CompileResult<()> {
1774        assert!(!ops.is_empty());
1775        assert_eq!(exprs.len(), ops.len());
1776        let (last_op, mid_ops) = ops.split_last().unwrap();
1777        let (last_val, mid_exprs) = exprs.split_last().unwrap();
1778
1779        use bytecode::ComparisonOperator::*;
1780        use bytecode::TestOperator::*;
1781        let compile_cmpop = |c: &mut Self, op: &located_ast::CmpOp| match op {
1782            located_ast::CmpOp::Eq => emit!(c, Instruction::CompareOperation { op: Equal }),
1783            located_ast::CmpOp::NotEq => emit!(c, Instruction::CompareOperation { op: NotEqual }),
1784            located_ast::CmpOp::Lt => emit!(c, Instruction::CompareOperation { op: Less }),
1785            located_ast::CmpOp::LtE => emit!(c, Instruction::CompareOperation { op: LessOrEqual }),
1786            located_ast::CmpOp::Gt => emit!(c, Instruction::CompareOperation { op: Greater }),
1787            located_ast::CmpOp::GtE => {
1788                emit!(c, Instruction::CompareOperation { op: GreaterOrEqual })
1789            }
1790            located_ast::CmpOp::In => emit!(c, Instruction::TestOperation { op: In }),
1791            located_ast::CmpOp::NotIn => emit!(c, Instruction::TestOperation { op: NotIn }),
1792            located_ast::CmpOp::Is => emit!(c, Instruction::TestOperation { op: Is }),
1793            located_ast::CmpOp::IsNot => emit!(c, Instruction::TestOperation { op: IsNot }),
1794        };
1795
1796        // a == b == c == d
1797        // compile into (pseudo code):
1798        // result = a == b
1799        // if result:
1800        //   result = b == c
1801        //   if result:
1802        //     result = c == d
1803
1804        // initialize lhs outside of loop
1805        self.compile_expression(left)?;
1806
1807        let end_blocks = if mid_exprs.is_empty() {
1808            None
1809        } else {
1810            let break_block = self.new_block();
1811            let after_block = self.new_block();
1812            Some((break_block, after_block))
1813        };
1814
1815        // for all comparisons except the last (as the last one doesn't need a conditional jump)
1816        for (op, val) in mid_ops.iter().zip(mid_exprs) {
1817            self.compile_expression(val)?;
1818            // store rhs for the next comparison in chain
1819            emit!(self, Instruction::Duplicate);
1820            emit!(self, Instruction::Rotate3);
1821
1822            compile_cmpop(self, op);
1823
1824            // if comparison result is false, we break with this value; if true, try the next one.
1825            if let Some((break_block, _)) = end_blocks {
1826                emit!(
1827                    self,
1828                    Instruction::JumpIfFalseOrPop {
1829                        target: break_block,
1830                    }
1831                );
1832            }
1833        }
1834
1835        // handle the last comparison
1836        self.compile_expression(last_val)?;
1837        compile_cmpop(self, last_op);
1838
1839        if let Some((break_block, after_block)) = end_blocks {
1840            emit!(
1841                self,
1842                Instruction::Jump {
1843                    target: after_block,
1844                }
1845            );
1846
1847            // early exit left us with stack: `rhs, comparison_result`. We need to clean up rhs.
1848            self.switch_to_block(break_block);
1849            emit!(self, Instruction::Rotate2);
1850            emit!(self, Instruction::Pop);
1851
1852            self.switch_to_block(after_block);
1853        }
1854
1855        Ok(())
1856    }
1857
1858    fn compile_annotation(&mut self, annotation: &located_ast::Expr) -> CompileResult<()> {
1859        if self.future_annotations {
1860            self.emit_load_const(ConstantData::Str {
1861                value: annotation.to_string(),
1862            });
1863        } else {
1864            self.compile_expression(annotation)?;
1865        }
1866        Ok(())
1867    }
1868
1869    fn compile_annotated_assign(
1870        &mut self,
1871        target: &located_ast::Expr,
1872        annotation: &located_ast::Expr,
1873        value: Option<&located_ast::Expr>,
1874    ) -> CompileResult<()> {
1875        if let Some(value) = value {
1876            self.compile_expression(value)?;
1877            self.compile_store(target)?;
1878        }
1879
1880        // Annotations are only evaluated in a module or class.
1881        if self.ctx.in_func() {
1882            return Ok(());
1883        }
1884
1885        // Compile annotation:
1886        self.compile_annotation(annotation)?;
1887
1888        if let located_ast::Expr::Name(located_ast::ExprName { id, .. }) = &target {
1889            // Store as dict entry in __annotations__ dict:
1890            let annotations = self.name("__annotations__");
1891            emit!(self, Instruction::LoadNameAny(annotations));
1892            self.emit_load_const(ConstantData::Str {
1893                value: self.mangle(id.as_str()).into_owned(),
1894            });
1895            emit!(self, Instruction::StoreSubscript);
1896        } else {
1897            // Drop annotation if not assigned to simple identifier.
1898            emit!(self, Instruction::Pop);
1899        }
1900
1901        Ok(())
1902    }
1903
1904    fn compile_store(&mut self, target: &located_ast::Expr) -> CompileResult<()> {
1905        match &target {
1906            located_ast::Expr::Name(located_ast::ExprName { id, .. }) => {
1907                self.store_name(id.as_str())?
1908            }
1909            located_ast::Expr::Subscript(located_ast::ExprSubscript { value, slice, .. }) => {
1910                self.compile_expression(value)?;
1911                self.compile_expression(slice)?;
1912                emit!(self, Instruction::StoreSubscript);
1913            }
1914            located_ast::Expr::Attribute(located_ast::ExprAttribute { value, attr, .. }) => {
1915                self.check_forbidden_name(attr.as_str(), NameUsage::Store)?;
1916                self.compile_expression(value)?;
1917                let idx = self.name(attr.as_str());
1918                emit!(self, Instruction::StoreAttr { idx });
1919            }
1920            located_ast::Expr::List(located_ast::ExprList { elts, .. })
1921            | located_ast::Expr::Tuple(located_ast::ExprTuple { elts, .. }) => {
1922                let mut seen_star = false;
1923
1924                // Scan for star args:
1925                for (i, element) in elts.iter().enumerate() {
1926                    if let located_ast::Expr::Starred(_) = &element {
1927                        if seen_star {
1928                            return Err(self.error(CodegenErrorType::MultipleStarArgs));
1929                        } else {
1930                            seen_star = true;
1931                            let before = i;
1932                            let after = elts.len() - i - 1;
1933                            let (before, after) = (|| Some((before.to_u8()?, after.to_u8()?)))()
1934                                .ok_or_else(|| {
1935                                    self.error_loc(
1936                                        CodegenErrorType::TooManyStarUnpack,
1937                                        target.location(),
1938                                    )
1939                                })?;
1940                            let args = bytecode::UnpackExArgs { before, after };
1941                            emit!(self, Instruction::UnpackEx { args });
1942                        }
1943                    }
1944                }
1945
1946                if !seen_star {
1947                    emit!(
1948                        self,
1949                        Instruction::UnpackSequence {
1950                            size: elts.len().to_u32(),
1951                        }
1952                    );
1953                }
1954
1955                for element in elts {
1956                    if let located_ast::Expr::Starred(located_ast::ExprStarred { value, .. }) =
1957                        &element
1958                    {
1959                        self.compile_store(value)?;
1960                    } else {
1961                        self.compile_store(element)?;
1962                    }
1963                }
1964            }
1965            _ => {
1966                return Err(self.error(match target {
1967                    located_ast::Expr::Starred(_) => CodegenErrorType::SyntaxError(
1968                        "starred assignment target must be in a list or tuple".to_owned(),
1969                    ),
1970                    _ => CodegenErrorType::Assign(target.python_name()),
1971                }));
1972            }
1973        }
1974
1975        Ok(())
1976    }
1977
1978    fn compile_augassign(
1979        &mut self,
1980        target: &located_ast::Expr,
1981        op: &located_ast::Operator,
1982        value: &located_ast::Expr,
1983    ) -> CompileResult<()> {
1984        enum AugAssignKind<'a> {
1985            Name { id: &'a str },
1986            Subscript,
1987            Attr { idx: bytecode::NameIdx },
1988        }
1989
1990        let kind = match &target {
1991            located_ast::Expr::Name(located_ast::ExprName { id, .. }) => {
1992                let id = id.as_str();
1993                self.compile_name(id, NameUsage::Load)?;
1994                AugAssignKind::Name { id }
1995            }
1996            located_ast::Expr::Subscript(located_ast::ExprSubscript { value, slice, .. }) => {
1997                self.compile_expression(value)?;
1998                self.compile_expression(slice)?;
1999                emit!(self, Instruction::Duplicate2);
2000                emit!(self, Instruction::Subscript);
2001                AugAssignKind::Subscript
2002            }
2003            located_ast::Expr::Attribute(located_ast::ExprAttribute { value, attr, .. }) => {
2004                let attr = attr.as_str();
2005                self.check_forbidden_name(attr, NameUsage::Store)?;
2006                self.compile_expression(value)?;
2007                emit!(self, Instruction::Duplicate);
2008                let idx = self.name(attr);
2009                emit!(self, Instruction::LoadAttr { idx });
2010                AugAssignKind::Attr { idx }
2011            }
2012            _ => {
2013                return Err(self.error(CodegenErrorType::Assign(target.python_name())));
2014            }
2015        };
2016
2017        self.compile_expression(value)?;
2018        self.compile_op(op, true);
2019
2020        match kind {
2021            AugAssignKind::Name { id } => {
2022                // stack: RESULT
2023                self.compile_name(id, NameUsage::Store)?;
2024            }
2025            AugAssignKind::Subscript => {
2026                // stack: CONTAINER SLICE RESULT
2027                emit!(self, Instruction::Rotate3);
2028                emit!(self, Instruction::StoreSubscript);
2029            }
2030            AugAssignKind::Attr { idx } => {
2031                // stack: CONTAINER RESULT
2032                emit!(self, Instruction::Rotate2);
2033                emit!(self, Instruction::StoreAttr { idx });
2034            }
2035        }
2036
2037        Ok(())
2038    }
2039
2040    fn compile_op(&mut self, op: &located_ast::Operator, inplace: bool) {
2041        let op = match op {
2042            located_ast::Operator::Add => bytecode::BinaryOperator::Add,
2043            located_ast::Operator::Sub => bytecode::BinaryOperator::Subtract,
2044            located_ast::Operator::Mult => bytecode::BinaryOperator::Multiply,
2045            located_ast::Operator::MatMult => bytecode::BinaryOperator::MatrixMultiply,
2046            located_ast::Operator::Div => bytecode::BinaryOperator::Divide,
2047            located_ast::Operator::FloorDiv => bytecode::BinaryOperator::FloorDivide,
2048            located_ast::Operator::Mod => bytecode::BinaryOperator::Modulo,
2049            located_ast::Operator::Pow => bytecode::BinaryOperator::Power,
2050            located_ast::Operator::LShift => bytecode::BinaryOperator::Lshift,
2051            located_ast::Operator::RShift => bytecode::BinaryOperator::Rshift,
2052            located_ast::Operator::BitOr => bytecode::BinaryOperator::Or,
2053            located_ast::Operator::BitXor => bytecode::BinaryOperator::Xor,
2054            located_ast::Operator::BitAnd => bytecode::BinaryOperator::And,
2055        };
2056        if inplace {
2057            emit!(self, Instruction::BinaryOperationInplace { op })
2058        } else {
2059            emit!(self, Instruction::BinaryOperation { op })
2060        }
2061    }
2062
2063    /// Implement boolean short circuit evaluation logic.
2064    /// https://en.wikipedia.org/wiki/Short-circuit_evaluation
2065    ///
2066    /// This means, in a boolean statement 'x and y' the variable y will
2067    /// not be evaluated when x is false.
2068    ///
2069    /// The idea is to jump to a label if the expression is either true or false
2070    /// (indicated by the condition parameter).
2071    fn compile_jump_if(
2072        &mut self,
2073        expression: &located_ast::Expr,
2074        condition: bool,
2075        target_block: ir::BlockIdx,
2076    ) -> CompileResult<()> {
2077        // Compile expression for test, and jump to label if false
2078        match &expression {
2079            located_ast::Expr::BoolOp(located_ast::ExprBoolOp { op, values, .. }) => {
2080                match op {
2081                    located_ast::BoolOp::And => {
2082                        if condition {
2083                            // If all values are true.
2084                            let end_block = self.new_block();
2085                            let (last_value, values) = values.split_last().unwrap();
2086
2087                            // If any of the values is false, we can short-circuit.
2088                            for value in values {
2089                                self.compile_jump_if(value, false, end_block)?;
2090                            }
2091
2092                            // It depends upon the last value now: will it be true?
2093                            self.compile_jump_if(last_value, true, target_block)?;
2094                            self.switch_to_block(end_block);
2095                        } else {
2096                            // If any value is false, the whole condition is false.
2097                            for value in values {
2098                                self.compile_jump_if(value, false, target_block)?;
2099                            }
2100                        }
2101                    }
2102                    located_ast::BoolOp::Or => {
2103                        if condition {
2104                            // If any of the values is true.
2105                            for value in values {
2106                                self.compile_jump_if(value, true, target_block)?;
2107                            }
2108                        } else {
2109                            // If all of the values are false.
2110                            let end_block = self.new_block();
2111                            let (last_value, values) = values.split_last().unwrap();
2112
2113                            // If any value is true, we can short-circuit:
2114                            for value in values {
2115                                self.compile_jump_if(value, true, end_block)?;
2116                            }
2117
2118                            // It all depends upon the last value now!
2119                            self.compile_jump_if(last_value, false, target_block)?;
2120                            self.switch_to_block(end_block);
2121                        }
2122                    }
2123                }
2124            }
2125            located_ast::Expr::UnaryOp(located_ast::ExprUnaryOp {
2126                op: located_ast::UnaryOp::Not,
2127                operand,
2128                ..
2129            }) => {
2130                self.compile_jump_if(operand, !condition, target_block)?;
2131            }
2132            _ => {
2133                // Fall back case which always will work!
2134                self.compile_expression(expression)?;
2135                if condition {
2136                    emit!(
2137                        self,
2138                        Instruction::JumpIfTrue {
2139                            target: target_block,
2140                        }
2141                    );
2142                } else {
2143                    emit!(
2144                        self,
2145                        Instruction::JumpIfFalse {
2146                            target: target_block,
2147                        }
2148                    );
2149                }
2150            }
2151        }
2152        Ok(())
2153    }
2154
2155    /// Compile a boolean operation as an expression.
2156    /// This means, that the last value remains on the stack.
2157    fn compile_bool_op(
2158        &mut self,
2159        op: &located_ast::BoolOp,
2160        values: &[located_ast::Expr],
2161    ) -> CompileResult<()> {
2162        let after_block = self.new_block();
2163
2164        let (last_value, values) = values.split_last().unwrap();
2165        for value in values {
2166            self.compile_expression(value)?;
2167
2168            match op {
2169                located_ast::BoolOp::And => {
2170                    emit!(
2171                        self,
2172                        Instruction::JumpIfFalseOrPop {
2173                            target: after_block,
2174                        }
2175                    );
2176                }
2177                located_ast::BoolOp::Or => {
2178                    emit!(
2179                        self,
2180                        Instruction::JumpIfTrueOrPop {
2181                            target: after_block,
2182                        }
2183                    );
2184                }
2185            }
2186        }
2187
2188        // If all values did not qualify, take the value of the last value:
2189        self.compile_expression(last_value)?;
2190        self.switch_to_block(after_block);
2191        Ok(())
2192    }
2193
2194    fn compile_dict(
2195        &mut self,
2196        keys: &[Option<located_ast::Expr>],
2197        values: &[located_ast::Expr],
2198    ) -> CompileResult<()> {
2199        let mut size = 0;
2200        let (packed, unpacked): (Vec<_>, Vec<_>) = keys
2201            .iter()
2202            .zip(values.iter())
2203            .partition(|(k, _)| k.is_some());
2204        for (key, value) in packed {
2205            self.compile_expression(key.as_ref().unwrap())?;
2206            self.compile_expression(value)?;
2207            size += 1;
2208        }
2209        emit!(self, Instruction::BuildMap { size });
2210
2211        for (_, value) in unpacked {
2212            self.compile_expression(value)?;
2213            emit!(self, Instruction::DictUpdate);
2214        }
2215
2216        Ok(())
2217    }
2218
2219    fn compile_expression(&mut self, expression: &located_ast::Expr) -> CompileResult<()> {
2220        use located_ast::*;
2221        trace!("Compiling {:?}", expression);
2222        let location = expression.location();
2223        self.set_source_location(location);
2224
2225        match &expression {
2226            Expr::Call(ExprCall {
2227                func,
2228                args,
2229                keywords,
2230                ..
2231            }) => self.compile_call(func, args, keywords)?,
2232            Expr::BoolOp(ExprBoolOp { op, values, .. }) => self.compile_bool_op(op, values)?,
2233            Expr::BinOp(ExprBinOp {
2234                left, op, right, ..
2235            }) => {
2236                self.compile_expression(left)?;
2237                self.compile_expression(right)?;
2238
2239                // Perform operation:
2240                self.compile_op(op, false);
2241            }
2242            Expr::Subscript(ExprSubscript { value, slice, .. }) => {
2243                self.compile_expression(value)?;
2244                self.compile_expression(slice)?;
2245                emit!(self, Instruction::Subscript);
2246            }
2247            Expr::UnaryOp(ExprUnaryOp { op, operand, .. }) => {
2248                self.compile_expression(operand)?;
2249
2250                // Perform operation:
2251                let op = match op {
2252                    UnaryOp::UAdd => bytecode::UnaryOperator::Plus,
2253                    UnaryOp::USub => bytecode::UnaryOperator::Minus,
2254                    UnaryOp::Not => bytecode::UnaryOperator::Not,
2255                    UnaryOp::Invert => bytecode::UnaryOperator::Invert,
2256                };
2257                emit!(self, Instruction::UnaryOperation { op });
2258            }
2259            Expr::Attribute(ExprAttribute { value, attr, .. }) => {
2260                self.compile_expression(value)?;
2261                let idx = self.name(attr.as_str());
2262                emit!(self, Instruction::LoadAttr { idx });
2263            }
2264            Expr::Compare(ExprCompare {
2265                left,
2266                ops,
2267                comparators,
2268                ..
2269            }) => {
2270                self.compile_chained_comparison(left, ops, comparators)?;
2271            }
2272            Expr::Constant(ExprConstant { value, .. }) => {
2273                self.emit_load_const(compile_constant(value));
2274            }
2275            Expr::List(ExprList { elts, .. }) => {
2276                let (size, unpack) = self.gather_elements(0, elts)?;
2277                if unpack {
2278                    emit!(self, Instruction::BuildListUnpack { size });
2279                } else {
2280                    emit!(self, Instruction::BuildList { size });
2281                }
2282            }
2283            Expr::Tuple(ExprTuple { elts, .. }) => {
2284                let (size, unpack) = self.gather_elements(0, elts)?;
2285                if unpack {
2286                    emit!(self, Instruction::BuildTupleUnpack { size });
2287                } else {
2288                    emit!(self, Instruction::BuildTuple { size });
2289                }
2290            }
2291            Expr::Set(ExprSet { elts, .. }) => {
2292                let (size, unpack) = self.gather_elements(0, elts)?;
2293                if unpack {
2294                    emit!(self, Instruction::BuildSetUnpack { size });
2295                } else {
2296                    emit!(self, Instruction::BuildSet { size });
2297                }
2298            }
2299            Expr::Dict(ExprDict { keys, values, .. }) => {
2300                self.compile_dict(keys, values)?;
2301            }
2302            Expr::Slice(ExprSlice {
2303                lower, upper, step, ..
2304            }) => {
2305                let mut compile_bound = |bound: Option<&located_ast::Expr>| match bound {
2306                    Some(exp) => self.compile_expression(exp),
2307                    None => {
2308                        self.emit_load_const(ConstantData::None);
2309                        Ok(())
2310                    }
2311                };
2312                compile_bound(lower.as_deref())?;
2313                compile_bound(upper.as_deref())?;
2314                if let Some(step) = step {
2315                    self.compile_expression(step)?;
2316                }
2317                let step = step.is_some();
2318                emit!(self, Instruction::BuildSlice { step });
2319            }
2320            Expr::Yield(ExprYield { value, .. }) => {
2321                if !self.ctx.in_func() {
2322                    return Err(self.error(CodegenErrorType::InvalidYield));
2323                }
2324                self.mark_generator();
2325                match value {
2326                    Some(expression) => self.compile_expression(expression)?,
2327                    Option::None => self.emit_load_const(ConstantData::None),
2328                };
2329                emit!(self, Instruction::YieldValue);
2330            }
2331            Expr::Await(ExprAwait { value, .. }) => {
2332                if self.ctx.func != FunctionContext::AsyncFunction {
2333                    return Err(self.error(CodegenErrorType::InvalidAwait));
2334                }
2335                self.compile_expression(value)?;
2336                emit!(self, Instruction::GetAwaitable);
2337                self.emit_load_const(ConstantData::None);
2338                emit!(self, Instruction::YieldFrom);
2339            }
2340            Expr::YieldFrom(ExprYieldFrom { value, .. }) => {
2341                match self.ctx.func {
2342                    FunctionContext::NoFunction => {
2343                        return Err(self.error(CodegenErrorType::InvalidYieldFrom));
2344                    }
2345                    FunctionContext::AsyncFunction => {
2346                        return Err(self.error(CodegenErrorType::AsyncYieldFrom));
2347                    }
2348                    FunctionContext::Function => {}
2349                }
2350                self.mark_generator();
2351                self.compile_expression(value)?;
2352                emit!(self, Instruction::GetIter);
2353                self.emit_load_const(ConstantData::None);
2354                emit!(self, Instruction::YieldFrom);
2355            }
2356            Expr::JoinedStr(ExprJoinedStr { values, .. }) => {
2357                if let Some(value) = try_get_constant_string(values) {
2358                    self.emit_load_const(ConstantData::Str { value })
2359                } else {
2360                    for value in values {
2361                        self.compile_expression(value)?;
2362                    }
2363                    emit!(
2364                        self,
2365                        Instruction::BuildString {
2366                            size: values.len().to_u32(),
2367                        }
2368                    )
2369                }
2370            }
2371            Expr::FormattedValue(ExprFormattedValue {
2372                value,
2373                conversion,
2374                format_spec,
2375                ..
2376            }) => {
2377                match format_spec {
2378                    Some(spec) => self.compile_expression(spec)?,
2379                    None => self.emit_load_const(ConstantData::Str {
2380                        value: String::new(),
2381                    }),
2382                };
2383                self.compile_expression(value)?;
2384                emit!(
2385                    self,
2386                    Instruction::FormatValue {
2387                        conversion: *conversion,
2388                    },
2389                );
2390            }
2391            Expr::Name(located_ast::ExprName { id, .. }) => self.load_name(id.as_str())?,
2392            Expr::Lambda(located_ast::ExprLambda { args, body, .. }) => {
2393                let prev_ctx = self.ctx;
2394
2395                let name = "<lambda>".to_owned();
2396                let mut func_flags = self.enter_function(&name, args)?;
2397
2398                self.ctx = CompileContext {
2399                    loop_data: Option::None,
2400                    in_class: prev_ctx.in_class,
2401                    func: FunctionContext::Function,
2402                };
2403
2404                self.current_code_info()
2405                    .constants
2406                    .insert_full(ConstantData::None);
2407
2408                self.compile_expression(body)?;
2409                self.emit_return_value();
2410                let code = self.pop_code_object();
2411                if self.build_closure(&code) {
2412                    func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
2413                }
2414                self.emit_load_const(ConstantData::Code {
2415                    code: Box::new(code),
2416                });
2417                self.emit_load_const(ConstantData::Str { value: name });
2418                // Turn code object into function object:
2419                emit!(self, Instruction::MakeFunction(func_flags));
2420
2421                self.ctx = prev_ctx;
2422            }
2423            Expr::ListComp(located_ast::ExprListComp {
2424                elt, generators, ..
2425            }) => {
2426                self.compile_comprehension(
2427                    "<listcomp>",
2428                    Some(Instruction::BuildList {
2429                        size: OpArgMarker::marker(),
2430                    }),
2431                    generators,
2432                    &|compiler| {
2433                        compiler.compile_comprehension_element(elt)?;
2434                        emit!(
2435                            compiler,
2436                            Instruction::ListAppend {
2437                                i: generators.len().to_u32(),
2438                            }
2439                        );
2440                        Ok(())
2441                    },
2442                    ComprehensionType::List,
2443                    Self::contains_await(elt),
2444                )?;
2445            }
2446            Expr::SetComp(located_ast::ExprSetComp {
2447                elt, generators, ..
2448            }) => {
2449                self.compile_comprehension(
2450                    "<setcomp>",
2451                    Some(Instruction::BuildSet {
2452                        size: OpArgMarker::marker(),
2453                    }),
2454                    generators,
2455                    &|compiler| {
2456                        compiler.compile_comprehension_element(elt)?;
2457                        emit!(
2458                            compiler,
2459                            Instruction::SetAdd {
2460                                i: generators.len().to_u32(),
2461                            }
2462                        );
2463                        Ok(())
2464                    },
2465                    ComprehensionType::Set,
2466                    Self::contains_await(elt),
2467                )?;
2468            }
2469            Expr::DictComp(located_ast::ExprDictComp {
2470                key,
2471                value,
2472                generators,
2473                ..
2474            }) => {
2475                self.compile_comprehension(
2476                    "<dictcomp>",
2477                    Some(Instruction::BuildMap {
2478                        size: OpArgMarker::marker(),
2479                    }),
2480                    generators,
2481                    &|compiler| {
2482                        // changed evaluation order for Py38 named expression PEP 572
2483                        compiler.compile_expression(key)?;
2484                        compiler.compile_expression(value)?;
2485
2486                        emit!(
2487                            compiler,
2488                            Instruction::MapAdd {
2489                                i: generators.len().to_u32(),
2490                            }
2491                        );
2492
2493                        Ok(())
2494                    },
2495                    ComprehensionType::Dict,
2496                    Self::contains_await(key) || Self::contains_await(value),
2497                )?;
2498            }
2499            Expr::GeneratorExp(located_ast::ExprGeneratorExp {
2500                elt, generators, ..
2501            }) => {
2502                self.compile_comprehension(
2503                    "<genexpr>",
2504                    None,
2505                    generators,
2506                    &|compiler| {
2507                        compiler.compile_comprehension_element(elt)?;
2508                        compiler.mark_generator();
2509                        emit!(compiler, Instruction::YieldValue);
2510                        emit!(compiler, Instruction::Pop);
2511
2512                        Ok(())
2513                    },
2514                    ComprehensionType::Generator,
2515                    Self::contains_await(elt),
2516                )?;
2517            }
2518            Expr::Starred(_) => {
2519                return Err(self.error(CodegenErrorType::InvalidStarExpr));
2520            }
2521            Expr::IfExp(located_ast::ExprIfExp {
2522                test, body, orelse, ..
2523            }) => {
2524                let else_block = self.new_block();
2525                let after_block = self.new_block();
2526                self.compile_jump_if(test, false, else_block)?;
2527
2528                // True case
2529                self.compile_expression(body)?;
2530                emit!(
2531                    self,
2532                    Instruction::Jump {
2533                        target: after_block,
2534                    }
2535                );
2536
2537                // False case
2538                self.switch_to_block(else_block);
2539                self.compile_expression(orelse)?;
2540
2541                // End
2542                self.switch_to_block(after_block);
2543            }
2544
2545            Expr::NamedExpr(located_ast::ExprNamedExpr {
2546                target,
2547                value,
2548                range: _,
2549            }) => {
2550                self.compile_expression(value)?;
2551                emit!(self, Instruction::Duplicate);
2552                self.compile_store(target)?;
2553            }
2554        }
2555        Ok(())
2556    }
2557
2558    fn compile_keywords(&mut self, keywords: &[located_ast::Keyword]) -> CompileResult<()> {
2559        let mut size = 0;
2560        let groupby = keywords.iter().group_by(|e| e.arg.is_none());
2561        for (is_unpacking, sub_keywords) in &groupby {
2562            if is_unpacking {
2563                for keyword in sub_keywords {
2564                    self.compile_expression(&keyword.value)?;
2565                    size += 1;
2566                }
2567            } else {
2568                let mut sub_size = 0;
2569                for keyword in sub_keywords {
2570                    if let Some(name) = &keyword.arg {
2571                        self.emit_load_const(ConstantData::Str {
2572                            value: name.to_string(),
2573                        });
2574                        self.compile_expression(&keyword.value)?;
2575                        sub_size += 1;
2576                    }
2577                }
2578                emit!(self, Instruction::BuildMap { size: sub_size });
2579                size += 1;
2580            }
2581        }
2582        if size > 1 {
2583            emit!(self, Instruction::BuildMapForCall { size });
2584        }
2585        Ok(())
2586    }
2587
2588    fn compile_call(
2589        &mut self,
2590        func: &located_ast::Expr,
2591        args: &[located_ast::Expr],
2592        keywords: &[located_ast::Keyword],
2593    ) -> CompileResult<()> {
2594        let method =
2595            if let located_ast::Expr::Attribute(located_ast::ExprAttribute {
2596                value, attr, ..
2597            }) = &func
2598            {
2599                self.compile_expression(value)?;
2600                let idx = self.name(attr.as_str());
2601                emit!(self, Instruction::LoadMethod { idx });
2602                true
2603            } else {
2604                self.compile_expression(func)?;
2605                false
2606            };
2607        let call = self.compile_call_inner(0, args, keywords)?;
2608        if method {
2609            self.compile_method_call(call)
2610        } else {
2611            self.compile_normal_call(call)
2612        }
2613        Ok(())
2614    }
2615
2616    fn compile_normal_call(&mut self, ty: CallType) {
2617        match ty {
2618            CallType::Positional { nargs } => {
2619                emit!(self, Instruction::CallFunctionPositional { nargs })
2620            }
2621            CallType::Keyword { nargs } => emit!(self, Instruction::CallFunctionKeyword { nargs }),
2622            CallType::Ex { has_kwargs } => emit!(self, Instruction::CallFunctionEx { has_kwargs }),
2623        }
2624    }
2625    fn compile_method_call(&mut self, ty: CallType) {
2626        match ty {
2627            CallType::Positional { nargs } => {
2628                emit!(self, Instruction::CallMethodPositional { nargs })
2629            }
2630            CallType::Keyword { nargs } => emit!(self, Instruction::CallMethodKeyword { nargs }),
2631            CallType::Ex { has_kwargs } => emit!(self, Instruction::CallMethodEx { has_kwargs }),
2632        }
2633    }
2634
2635    fn compile_call_inner(
2636        &mut self,
2637        additional_positional: u32,
2638        args: &[located_ast::Expr],
2639        keywords: &[located_ast::Keyword],
2640    ) -> CompileResult<CallType> {
2641        let count = (args.len() + keywords.len()).to_u32() + additional_positional;
2642
2643        // Normal arguments:
2644        let (size, unpack) = self.gather_elements(additional_positional, args)?;
2645        let has_double_star = keywords.iter().any(|k| k.arg.is_none());
2646
2647        for keyword in keywords {
2648            if let Some(name) = &keyword.arg {
2649                self.check_forbidden_name(name.as_str(), NameUsage::Store)?;
2650            }
2651        }
2652
2653        let call = if unpack || has_double_star {
2654            // Create a tuple with positional args:
2655            if unpack {
2656                emit!(self, Instruction::BuildTupleUnpack { size });
2657            } else {
2658                emit!(self, Instruction::BuildTuple { size });
2659            }
2660
2661            // Create an optional map with kw-args:
2662            let has_kwargs = !keywords.is_empty();
2663            if has_kwargs {
2664                self.compile_keywords(keywords)?;
2665            }
2666            CallType::Ex { has_kwargs }
2667        } else if !keywords.is_empty() {
2668            let mut kwarg_names = vec![];
2669            for keyword in keywords {
2670                if let Some(name) = &keyword.arg {
2671                    kwarg_names.push(ConstantData::Str {
2672                        value: name.to_string(),
2673                    });
2674                } else {
2675                    // This means **kwargs!
2676                    panic!("name must be set");
2677                }
2678                self.compile_expression(&keyword.value)?;
2679            }
2680
2681            self.emit_load_const(ConstantData::Tuple {
2682                elements: kwarg_names,
2683            });
2684            CallType::Keyword { nargs: count }
2685        } else {
2686            CallType::Positional { nargs: count }
2687        };
2688
2689        Ok(call)
2690    }
2691
2692    // Given a vector of expr / star expr generate code which gives either
2693    // a list of expressions on the stack, or a list of tuples.
2694    fn gather_elements(
2695        &mut self,
2696        before: u32,
2697        elements: &[located_ast::Expr],
2698    ) -> CompileResult<(u32, bool)> {
2699        // First determine if we have starred elements:
2700        let has_stars = elements
2701            .iter()
2702            .any(|e| matches!(e, located_ast::Expr::Starred(_)));
2703
2704        let size = if has_stars {
2705            let mut size = 0;
2706
2707            if before > 0 {
2708                emit!(self, Instruction::BuildTuple { size: before });
2709                size += 1;
2710            }
2711
2712            let groups = elements
2713                .iter()
2714                .map(|element| {
2715                    if let located_ast::Expr::Starred(located_ast::ExprStarred { value, .. }) =
2716                        &element
2717                    {
2718                        (true, value.as_ref())
2719                    } else {
2720                        (false, element)
2721                    }
2722                })
2723                .group_by(|(starred, _)| *starred);
2724
2725            for (starred, run) in &groups {
2726                let mut run_size = 0;
2727                for (_, value) in run {
2728                    self.compile_expression(value)?;
2729                    run_size += 1
2730                }
2731                if starred {
2732                    size += run_size
2733                } else {
2734                    emit!(self, Instruction::BuildTuple { size: run_size });
2735                    size += 1
2736                }
2737            }
2738
2739            size
2740        } else {
2741            for element in elements {
2742                self.compile_expression(element)?;
2743            }
2744            before + elements.len().to_u32()
2745        };
2746
2747        Ok((size, has_stars))
2748    }
2749
2750    fn compile_comprehension_element(&mut self, element: &located_ast::Expr) -> CompileResult<()> {
2751        self.compile_expression(element).map_err(|e| {
2752            if let CodegenErrorType::InvalidStarExpr = e.error {
2753                self.error(CodegenErrorType::SyntaxError(
2754                    "iterable unpacking cannot be used in comprehension".to_owned(),
2755                ))
2756            } else {
2757                e
2758            }
2759        })
2760    }
2761
2762    fn compile_comprehension(
2763        &mut self,
2764        name: &str,
2765        init_collection: Option<Instruction>,
2766        generators: &[located_ast::Comprehension],
2767        compile_element: &dyn Fn(&mut Self) -> CompileResult<()>,
2768        comprehension_type: ComprehensionType,
2769        element_contains_await: bool,
2770    ) -> CompileResult<()> {
2771        let prev_ctx = self.ctx;
2772        let has_an_async_gen = generators.iter().any(|g| g.is_async);
2773
2774        // async comprehensions are allowed in various contexts:
2775        // - list/set/dict comprehensions in async functions
2776        // - always for generator expressions
2777        // Note: generators have to be treated specially since their async version is a fundamentally
2778        // different type (aiter vs iter) instead of just an awaitable.
2779
2780        // for if it actually is async, we check if any generator is async or if the element contains await
2781
2782        // if the element expression contains await, but the context doesn't allow for async,
2783        // then we continue on here with is_async=false and will produce a syntax once the await is hit
2784
2785        let is_async_list_set_dict_comprehension = comprehension_type
2786            != ComprehensionType::Generator
2787            && (has_an_async_gen || element_contains_await) // does it have to be async? (uses await or async for)
2788            && prev_ctx.func == FunctionContext::AsyncFunction; // is it allowed to be async? (in an async function)
2789
2790        let is_async_generator_comprehension = comprehension_type == ComprehensionType::Generator
2791            && (has_an_async_gen || element_contains_await);
2792
2793        // since one is for generators, and one for not generators, they should never both be true
2794        debug_assert!(!(is_async_list_set_dict_comprehension && is_async_generator_comprehension));
2795
2796        let is_async = is_async_list_set_dict_comprehension || is_async_generator_comprehension;
2797
2798        self.ctx = CompileContext {
2799            loop_data: None,
2800            in_class: prev_ctx.in_class,
2801            func: if is_async {
2802                FunctionContext::AsyncFunction
2803            } else {
2804                FunctionContext::Function
2805            },
2806        };
2807
2808        // We must have at least one generator:
2809        assert!(!generators.is_empty());
2810
2811        let flags = bytecode::CodeFlags::NEW_LOCALS | bytecode::CodeFlags::IS_OPTIMIZED;
2812        let flags = if is_async {
2813            flags | bytecode::CodeFlags::IS_COROUTINE
2814        } else {
2815            flags
2816        };
2817
2818        // Create magnificent function <listcomp>:
2819        self.push_output(flags, 1, 1, 0, name.to_owned());
2820        let arg0 = self.varname(".0")?;
2821
2822        let return_none = init_collection.is_none();
2823        // Create empty object of proper type:
2824        if let Some(init_collection) = init_collection {
2825            self._emit(init_collection, OpArg(0), ir::BlockIdx::NULL)
2826        }
2827
2828        let mut loop_labels = vec![];
2829        for generator in generators {
2830            let loop_block = self.new_block();
2831            let after_block = self.new_block();
2832
2833            // emit!(self, Instruction::SetupLoop);
2834
2835            if loop_labels.is_empty() {
2836                // Load iterator onto stack (passed as first argument):
2837                emit!(self, Instruction::LoadFast(arg0));
2838            } else {
2839                // Evaluate iterated item:
2840                self.compile_expression(&generator.iter)?;
2841
2842                // Get iterator / turn item into an iterator
2843                if generator.is_async {
2844                    emit!(self, Instruction::GetAIter);
2845                } else {
2846                    emit!(self, Instruction::GetIter);
2847                }
2848            }
2849
2850            loop_labels.push((loop_block, after_block));
2851            self.switch_to_block(loop_block);
2852            if generator.is_async {
2853                emit!(
2854                    self,
2855                    Instruction::SetupExcept {
2856                        handler: after_block,
2857                    }
2858                );
2859                emit!(self, Instruction::GetANext);
2860                self.emit_load_const(ConstantData::None);
2861                emit!(self, Instruction::YieldFrom);
2862                self.compile_store(&generator.target)?;
2863                emit!(self, Instruction::PopBlock);
2864            } else {
2865                emit!(
2866                    self,
2867                    Instruction::ForIter {
2868                        target: after_block,
2869                    }
2870                );
2871                self.compile_store(&generator.target)?;
2872            }
2873
2874            // Now evaluate the ifs:
2875            for if_condition in &generator.ifs {
2876                self.compile_jump_if(if_condition, false, loop_block)?
2877            }
2878        }
2879
2880        compile_element(self)?;
2881
2882        for (loop_block, after_block) in loop_labels.iter().rev().copied() {
2883            // Repeat:
2884            emit!(self, Instruction::Jump { target: loop_block });
2885
2886            // End of for loop:
2887            self.switch_to_block(after_block);
2888            if has_an_async_gen {
2889                emit!(self, Instruction::EndAsyncFor);
2890            }
2891        }
2892
2893        if return_none {
2894            self.emit_load_const(ConstantData::None)
2895        }
2896
2897        // Return freshly filled list:
2898        self.emit_return_value();
2899
2900        // Fetch code for listcomp function:
2901        let code = self.pop_code_object();
2902
2903        self.ctx = prev_ctx;
2904
2905        let mut func_flags = bytecode::MakeFunctionFlags::empty();
2906        if self.build_closure(&code) {
2907            func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
2908        }
2909
2910        // List comprehension code:
2911        self.emit_load_const(ConstantData::Code {
2912            code: Box::new(code),
2913        });
2914
2915        // List comprehension function name:
2916        self.emit_load_const(ConstantData::Str {
2917            value: name.to_owned(),
2918        });
2919
2920        // Turn code object into function object:
2921        emit!(self, Instruction::MakeFunction(func_flags));
2922
2923        // Evaluate iterated item:
2924        self.compile_expression(&generators[0].iter)?;
2925
2926        // Get iterator / turn item into an iterator
2927        if has_an_async_gen {
2928            emit!(self, Instruction::GetAIter);
2929        } else {
2930            emit!(self, Instruction::GetIter);
2931        };
2932
2933        // Call just created <listcomp> function:
2934        emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
2935        if is_async_list_set_dict_comprehension {
2936            // async, but not a generator and not an async for
2937            // in this case, we end up with an awaitable
2938            // that evaluates to the list/set/dict, so here we add an await
2939            emit!(self, Instruction::GetAwaitable);
2940            self.emit_load_const(ConstantData::None);
2941            emit!(self, Instruction::YieldFrom);
2942        }
2943
2944        Ok(())
2945    }
2946
2947    fn compile_future_features(
2948        &mut self,
2949        features: &[located_ast::Alias],
2950    ) -> Result<(), CodegenError> {
2951        if self.done_with_future_stmts {
2952            return Err(self.error(CodegenErrorType::InvalidFuturePlacement));
2953        }
2954        for feature in features {
2955            match feature.name.as_str() {
2956                // Python 3 features; we've already implemented them by default
2957                "nested_scopes" | "generators" | "division" | "absolute_import"
2958                | "with_statement" | "print_function" | "unicode_literals" | "generator_stop" => {}
2959                "annotations" => self.future_annotations = true,
2960                other => {
2961                    return Err(self.error(CodegenErrorType::InvalidFutureFeature(other.to_owned())))
2962                }
2963            }
2964        }
2965        Ok(())
2966    }
2967
2968    // Low level helper functions:
2969    fn _emit(&mut self, instr: Instruction, arg: OpArg, target: ir::BlockIdx) {
2970        let location = self.current_source_location;
2971        // TODO: insert source filename
2972        self.current_block().instructions.push(ir::InstructionInfo {
2973            instr,
2974            arg,
2975            target,
2976            location,
2977        });
2978    }
2979
2980    fn emit_no_arg(&mut self, ins: Instruction) {
2981        self._emit(ins, OpArg::null(), ir::BlockIdx::NULL)
2982    }
2983
2984    fn emit_arg<A: OpArgType, T: EmitArg<A>>(
2985        &mut self,
2986        arg: T,
2987        f: impl FnOnce(OpArgMarker<A>) -> Instruction,
2988    ) {
2989        let (op, arg, target) = arg.emit(f);
2990        self._emit(op, arg, target)
2991    }
2992
2993    // fn block_done()
2994
2995    fn arg_constant(&mut self, constant: ConstantData) -> u32 {
2996        let info = self.current_code_info();
2997        info.constants.insert_full(constant).0.to_u32()
2998    }
2999
3000    fn emit_load_const(&mut self, constant: ConstantData) {
3001        let idx = self.arg_constant(constant);
3002        self.emit_arg(idx, |idx| Instruction::LoadConst { idx })
3003    }
3004
3005    fn emit_return_const(&mut self, constant: ConstantData) {
3006        let idx = self.arg_constant(constant);
3007        self.emit_arg(idx, |idx| Instruction::ReturnConst { idx })
3008    }
3009
3010    fn emit_return_value(&mut self) {
3011        if let Some(inst) = self.current_block().instructions.last_mut() {
3012            if let Instruction::LoadConst { idx } = inst.instr {
3013                inst.instr = Instruction::ReturnConst { idx };
3014                return;
3015            }
3016        }
3017        emit!(self, Instruction::ReturnValue)
3018    }
3019
3020    fn current_code_info(&mut self) -> &mut ir::CodeInfo {
3021        self.code_stack.last_mut().expect("no code on stack")
3022    }
3023
3024    fn current_block(&mut self) -> &mut ir::Block {
3025        let info = self.current_code_info();
3026        &mut info.blocks[info.current_block]
3027    }
3028
3029    fn new_block(&mut self) -> ir::BlockIdx {
3030        let code = self.current_code_info();
3031        let idx = ir::BlockIdx(code.blocks.len().to_u32());
3032        code.blocks.push(ir::Block::default());
3033        idx
3034    }
3035
3036    fn switch_to_block(&mut self, block: ir::BlockIdx) {
3037        let code = self.current_code_info();
3038        let prev = code.current_block;
3039        assert_eq!(
3040            code.blocks[block].next,
3041            ir::BlockIdx::NULL,
3042            "switching to completed block"
3043        );
3044        let prev_block = &mut code.blocks[prev.0 as usize];
3045        assert_eq!(
3046            prev_block.next.0,
3047            u32::MAX,
3048            "switching from block that's already got a next"
3049        );
3050        prev_block.next = block;
3051        code.current_block = block;
3052    }
3053
3054    fn set_source_location(&mut self, location: SourceLocation) {
3055        self.current_source_location = location;
3056    }
3057
3058    fn get_source_line_number(&mut self) -> LineNumber {
3059        let location = self.current_source_location;
3060        location.row
3061    }
3062
3063    fn push_qualified_path(&mut self, name: &str) {
3064        self.qualified_path.push(name.to_owned());
3065    }
3066
3067    fn mark_generator(&mut self) {
3068        self.current_code_info().flags |= bytecode::CodeFlags::IS_GENERATOR
3069    }
3070
3071    /// Whether the expression contains an await expression and
3072    /// thus requires the function to be async.
3073    /// Async with and async for are statements, so I won't check for them here
3074    fn contains_await(expression: &located_ast::Expr) -> bool {
3075        use located_ast::*;
3076
3077        match &expression {
3078            Expr::Call(ExprCall {
3079                func,
3080                args,
3081                keywords,
3082                ..
3083            }) => {
3084                Self::contains_await(func)
3085                    || args.iter().any(Self::contains_await)
3086                    || keywords.iter().any(|kw| Self::contains_await(&kw.value))
3087            }
3088            Expr::BoolOp(ExprBoolOp { values, .. }) => values.iter().any(Self::contains_await),
3089            Expr::BinOp(ExprBinOp { left, right, .. }) => {
3090                Self::contains_await(left) || Self::contains_await(right)
3091            }
3092            Expr::Subscript(ExprSubscript { value, slice, .. }) => {
3093                Self::contains_await(value) || Self::contains_await(slice)
3094            }
3095            Expr::UnaryOp(ExprUnaryOp { operand, .. }) => Self::contains_await(operand),
3096            Expr::Attribute(ExprAttribute { value, .. }) => Self::contains_await(value),
3097            Expr::Compare(ExprCompare {
3098                left, comparators, ..
3099            }) => Self::contains_await(left) || comparators.iter().any(Self::contains_await),
3100            Expr::Constant(ExprConstant { .. }) => false,
3101            Expr::List(ExprList { elts, .. }) => elts.iter().any(Self::contains_await),
3102            Expr::Tuple(ExprTuple { elts, .. }) => elts.iter().any(Self::contains_await),
3103            Expr::Set(ExprSet { elts, .. }) => elts.iter().any(Self::contains_await),
3104            Expr::Dict(ExprDict { keys, values, .. }) => {
3105                keys.iter()
3106                    .any(|key| key.as_ref().map_or(false, Self::contains_await))
3107                    || values.iter().any(Self::contains_await)
3108            }
3109            Expr::Slice(ExprSlice {
3110                lower, upper, step, ..
3111            }) => {
3112                lower.as_ref().map_or(false, |l| Self::contains_await(l))
3113                    || upper.as_ref().map_or(false, |u| Self::contains_await(u))
3114                    || step.as_ref().map_or(false, |s| Self::contains_await(s))
3115            }
3116            Expr::Yield(ExprYield { value, .. }) => {
3117                value.as_ref().map_or(false, |v| Self::contains_await(v))
3118            }
3119            Expr::Await(ExprAwait { .. }) => true,
3120            Expr::YieldFrom(ExprYieldFrom { value, .. }) => Self::contains_await(value),
3121            Expr::JoinedStr(ExprJoinedStr { values, .. }) => {
3122                values.iter().any(Self::contains_await)
3123            }
3124            Expr::FormattedValue(ExprFormattedValue {
3125                value,
3126                conversion: _,
3127                format_spec,
3128                ..
3129            }) => {
3130                Self::contains_await(value)
3131                    || format_spec
3132                        .as_ref()
3133                        .map_or(false, |fs| Self::contains_await(fs))
3134            }
3135            Expr::Name(located_ast::ExprName { .. }) => false,
3136            Expr::Lambda(located_ast::ExprLambda { body, .. }) => Self::contains_await(body),
3137            Expr::ListComp(located_ast::ExprListComp {
3138                elt, generators, ..
3139            }) => {
3140                Self::contains_await(elt)
3141                    || generators.iter().any(|gen| Self::contains_await(&gen.iter))
3142            }
3143            Expr::SetComp(located_ast::ExprSetComp {
3144                elt, generators, ..
3145            }) => {
3146                Self::contains_await(elt)
3147                    || generators.iter().any(|gen| Self::contains_await(&gen.iter))
3148            }
3149            Expr::DictComp(located_ast::ExprDictComp {
3150                key,
3151                value,
3152                generators,
3153                ..
3154            }) => {
3155                Self::contains_await(key)
3156                    || Self::contains_await(value)
3157                    || generators.iter().any(|gen| Self::contains_await(&gen.iter))
3158            }
3159            Expr::GeneratorExp(located_ast::ExprGeneratorExp {
3160                elt, generators, ..
3161            }) => {
3162                Self::contains_await(elt)
3163                    || generators.iter().any(|gen| Self::contains_await(&gen.iter))
3164            }
3165            Expr::Starred(expr) => Self::contains_await(&expr.value),
3166            Expr::IfExp(located_ast::ExprIfExp {
3167                test, body, orelse, ..
3168            }) => {
3169                Self::contains_await(test)
3170                    || Self::contains_await(body)
3171                    || Self::contains_await(orelse)
3172            }
3173
3174            Expr::NamedExpr(located_ast::ExprNamedExpr {
3175                target,
3176                value,
3177                range: _,
3178            }) => Self::contains_await(target) || Self::contains_await(value),
3179        }
3180    }
3181}
3182
3183trait EmitArg<Arg: OpArgType> {
3184    fn emit(
3185        self,
3186        f: impl FnOnce(OpArgMarker<Arg>) -> Instruction,
3187    ) -> (Instruction, OpArg, ir::BlockIdx);
3188}
3189impl<T: OpArgType> EmitArg<T> for T {
3190    fn emit(
3191        self,
3192        f: impl FnOnce(OpArgMarker<T>) -> Instruction,
3193    ) -> (Instruction, OpArg, ir::BlockIdx) {
3194        let (marker, arg) = OpArgMarker::new(self);
3195        (f(marker), arg, ir::BlockIdx::NULL)
3196    }
3197}
3198impl EmitArg<bytecode::Label> for ir::BlockIdx {
3199    fn emit(
3200        self,
3201        f: impl FnOnce(OpArgMarker<bytecode::Label>) -> Instruction,
3202    ) -> (Instruction, OpArg, ir::BlockIdx) {
3203        (f(OpArgMarker::marker()), OpArg::null(), self)
3204    }
3205}
3206
3207fn split_doc<'a>(
3208    body: &'a [located_ast::Stmt],
3209    opts: &CompileOpts,
3210) -> (Option<String>, &'a [located_ast::Stmt]) {
3211    if let Some((located_ast::Stmt::Expr(expr), body_rest)) = body.split_first() {
3212        if let Some(doc) = try_get_constant_string(std::slice::from_ref(&expr.value)) {
3213            if opts.optimize < 2 {
3214                return (Some(doc), body_rest);
3215            } else {
3216                return (None, body_rest);
3217            }
3218        }
3219    }
3220    (None, body)
3221}
3222
3223fn try_get_constant_string(values: &[located_ast::Expr]) -> Option<String> {
3224    fn get_constant_string_inner(out_string: &mut String, value: &located_ast::Expr) -> bool {
3225        match value {
3226            located_ast::Expr::Constant(located_ast::ExprConstant {
3227                value: located_ast::Constant::Str(s),
3228                ..
3229            }) => {
3230                out_string.push_str(s);
3231                true
3232            }
3233            located_ast::Expr::JoinedStr(located_ast::ExprJoinedStr { values, .. }) => values
3234                .iter()
3235                .all(|value| get_constant_string_inner(out_string, value)),
3236            _ => false,
3237        }
3238    }
3239    let mut out_string = String::new();
3240    if values
3241        .iter()
3242        .all(|v| get_constant_string_inner(&mut out_string, v))
3243    {
3244        Some(out_string)
3245    } else {
3246        None
3247    }
3248}
3249
3250fn compile_constant(value: &located_ast::Constant) -> ConstantData {
3251    match value {
3252        located_ast::Constant::None => ConstantData::None,
3253        located_ast::Constant::Bool(b) => ConstantData::Boolean { value: *b },
3254        located_ast::Constant::Str(s) => ConstantData::Str { value: s.clone() },
3255        located_ast::Constant::Bytes(b) => ConstantData::Bytes { value: b.clone() },
3256        located_ast::Constant::Int(i) => ConstantData::Integer { value: i.clone() },
3257        located_ast::Constant::Tuple(t) => ConstantData::Tuple {
3258            elements: t.iter().map(compile_constant).collect(),
3259        },
3260        located_ast::Constant::Float(f) => ConstantData::Float { value: *f },
3261        located_ast::Constant::Complex { real, imag } => ConstantData::Complex {
3262            value: Complex64::new(*real, *imag),
3263        },
3264        located_ast::Constant::Ellipsis => ConstantData::Ellipsis,
3265    }
3266}
3267
3268// Note: Not a good practice in general. Keep this trait private only for compiler
3269trait ToU32 {
3270    fn to_u32(self) -> u32;
3271}
3272
3273impl ToU32 for usize {
3274    fn to_u32(self) -> u32 {
3275        self.try_into().unwrap()
3276    }
3277}
3278
3279#[cfg(test)]
3280mod tests {
3281    use super::*;
3282    use rustpython_parser::ast::Suite;
3283    use rustpython_parser::Parse;
3284    use rustpython_parser_core::source_code::LinearLocator;
3285
3286    fn compile_exec(source: &str) -> CodeObject {
3287        let mut locator: LinearLocator = LinearLocator::new(source);
3288        use rustpython_parser::ast::fold::Fold;
3289        let mut compiler: Compiler = Compiler::new(
3290            CompileOpts::default(),
3291            "source_path".to_owned(),
3292            "<module>".to_owned(),
3293        );
3294        let ast = Suite::parse(source, "<test>").unwrap();
3295        let ast = locator.fold(ast).unwrap();
3296        let symbol_scope = SymbolTable::scan_program(&ast).unwrap();
3297        compiler.compile_program(&ast, symbol_scope).unwrap();
3298        compiler.pop_code_object()
3299    }
3300
3301    macro_rules! assert_dis_snapshot {
3302        ($value:expr) => {
3303            insta::assert_snapshot!(
3304                insta::internals::AutoName,
3305                $value.display_expand_code_objects().to_string(),
3306                stringify!($value)
3307            )
3308        };
3309    }
3310
3311    #[test]
3312    fn test_if_ors() {
3313        assert_dis_snapshot!(compile_exec(
3314            "\
3315if True or False or False:
3316    pass
3317"
3318        ));
3319    }
3320
3321    #[test]
3322    fn test_if_ands() {
3323        assert_dis_snapshot!(compile_exec(
3324            "\
3325if True and False and False:
3326    pass
3327"
3328        ));
3329    }
3330
3331    #[test]
3332    fn test_if_mixed() {
3333        assert_dis_snapshot!(compile_exec(
3334            "\
3335if (True and False) or (False and True):
3336    pass
3337"
3338        ));
3339    }
3340
3341    #[test]
3342    fn test_nested_double_async_with() {
3343        assert_dis_snapshot!(compile_exec(
3344            "\
3345for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):
3346    with self.subTest(type=type(stop_exc)):
3347        try:
3348            async with egg():
3349                raise stop_exc
3350        except Exception as ex:
3351            self.assertIs(ex, stop_exc)
3352        else:
3353            self.fail(f'{stop_exc} was suppressed')
3354"
3355        ));
3356    }
3357}