1#![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 const BUILTIN_CONSTANTS: &[&str] = &["__debug__"];
45
46 BUILTIN_CONSTANTS.contains(&name)
47}
48
49struct 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 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
98pub 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
121fn 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
141pub 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
156pub 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 fn push_symbol_table(&mut self) -> &SymbolTable {
264 let table = self
266 .symbol_table_stack
267 .last_mut()
268 .expect("no next symbol table")
269 .sub_tables
270 .remove(0);
271 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 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 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 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(); }
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(); 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 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 } };
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 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 _ => self.done_with_future_stmts = true,
593 }
594
595 match &statement {
596 Stmt::Import(StmtImport { names, .. }) => {
597 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 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 emit!(self, Instruction::ImportStar);
662 } else {
663 for name in names {
666 let name = &name;
667 let idx = self.name(name.name.as_str());
668 emit!(self, Instruction::ImportFrom { idx });
670
671 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 emit!(self, Instruction::Pop);
681 }
682 }
683 Stmt::Expr(StmtExpr { value, .. }) => {
684 self.compile_expression(value)?;
685
686 emit!(self, Instruction::Pop);
688 }
689 Stmt::Global(_) | Stmt::Nonlocal(_) => {
690 }
692 Stmt::If(StmtIf {
693 test, body, orelse, ..
694 }) => {
695 let after_block = self.new_block();
696 if orelse.is_empty() {
697 self.compile_jump_if(test, false, after_block)?;
699 self.compile_statements(body)?;
700 } else {
701 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 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 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 }
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 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 for _ in decorator_list {
1057 emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
1058 }
1059 }
1060
1061 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.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 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 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 self.switch_to_block(handler_block);
1137 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 let Some(exc_type) = type_ {
1149 emit!(self, Instruction::Duplicate);
1151
1152 self.compile_expression(exc_type)?;
1154 emit!(
1155 self,
1156 Instruction::TestOperation {
1157 op: bytecode::TestOperator::ExceptionMatch,
1158 }
1159 );
1160
1161 emit!(
1163 self,
1164 Instruction::JumpIfFalse {
1165 target: next_handler,
1166 }
1167 );
1168
1169 if let Some(alias) = name {
1171 self.store_name(alias.as_str())?
1172 } else {
1173 emit!(self, Instruction::Pop);
1175 }
1176 } else {
1177 emit!(self, Instruction::Pop);
1180 }
1181
1182 self.compile_statements(body)?;
1184 emit!(self, Instruction::PopException);
1185
1186 if !finalbody.is_empty() {
1187 emit!(self, Instruction::PopBlock); emit!(self, Instruction::EnterFinally);
1190 }
1191
1192 emit!(
1193 self,
1194 Instruction::Jump {
1195 target: finally_block,
1196 }
1197 );
1198
1199 self.switch_to_block(next_handler);
1201 }
1202
1203 emit!(
1206 self,
1207 Instruction::Raise {
1208 kind: bytecode::RaiseKind::Reraise,
1209 }
1210 );
1211
1212 self.switch_to_block(else_block);
1215 self.compile_statements(orelse)?;
1216
1217 if !finalbody.is_empty() {
1218 emit!(self, Instruction::PopBlock); emit!(self, Instruction::EnterFinally);
1222 }
1223
1224 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>, is_async: bool,
1257 type_params: &[located_ast::TypeParam],
1258 ) -> CompileResult<()> {
1259 self.prepare_decorators(decorator_list)?;
1260
1261 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 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 match body.last() {
1298 Some(located_ast::Stmt::Return(_)) => {
1299 }
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 if !type_params.is_empty() {
1313 self.compile_type_params(type_params)?;
1314 func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
1315 }
1316
1317 let mut num_annotations = 0;
1319
1320 if let Some(annotation) = returns {
1322 self.emit_load_const(ConstantData::Str {
1324 value: "return".to_owned(),
1325 });
1326 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 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 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 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 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 !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 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 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 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 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 self.emit_load_const(match doc_str {
1591 Some(doc) => ConstantData::Str { value: doc },
1592 None => ConstantData::None, });
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 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 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 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 emit!(self, Instruction::GetIter);
1733
1734 self.switch_to_block(for_block);
1735 emit!(self, Instruction::ForIter { target: else_block });
1736
1737 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 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 (op, val) in mid_ops.iter().zip(mid_exprs) {
1817 self.compile_expression(val)?;
1818 emit!(self, Instruction::Duplicate);
1820 emit!(self, Instruction::Rotate3);
1821
1822 compile_cmpop(self, op);
1823
1824 if let Some((break_block, _)) = end_blocks {
1826 emit!(
1827 self,
1828 Instruction::JumpIfFalseOrPop {
1829 target: break_block,
1830 }
1831 );
1832 }
1833 }
1834
1835 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 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 if self.ctx.in_func() {
1882 return Ok(());
1883 }
1884
1885 self.compile_annotation(annotation)?;
1887
1888 if let located_ast::Expr::Name(located_ast::ExprName { id, .. }) = &target {
1889 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 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 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 self.compile_name(id, NameUsage::Store)?;
2024 }
2025 AugAssignKind::Subscript => {
2026 emit!(self, Instruction::Rotate3);
2028 emit!(self, Instruction::StoreSubscript);
2029 }
2030 AugAssignKind::Attr { idx } => {
2031 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 fn compile_jump_if(
2072 &mut self,
2073 expression: &located_ast::Expr,
2074 condition: bool,
2075 target_block: ir::BlockIdx,
2076 ) -> CompileResult<()> {
2077 match &expression {
2079 located_ast::Expr::BoolOp(located_ast::ExprBoolOp { op, values, .. }) => {
2080 match op {
2081 located_ast::BoolOp::And => {
2082 if condition {
2083 let end_block = self.new_block();
2085 let (last_value, values) = values.split_last().unwrap();
2086
2087 for value in values {
2089 self.compile_jump_if(value, false, end_block)?;
2090 }
2091
2092 self.compile_jump_if(last_value, true, target_block)?;
2094 self.switch_to_block(end_block);
2095 } else {
2096 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 for value in values {
2106 self.compile_jump_if(value, true, target_block)?;
2107 }
2108 } else {
2109 let end_block = self.new_block();
2111 let (last_value, values) = values.split_last().unwrap();
2112
2113 for value in values {
2115 self.compile_jump_if(value, true, end_block)?;
2116 }
2117
2118 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 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 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 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 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 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 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 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 self.compile_expression(body)?;
2530 emit!(
2531 self,
2532 Instruction::Jump {
2533 target: after_block,
2534 }
2535 );
2536
2537 self.switch_to_block(else_block);
2539 self.compile_expression(orelse)?;
2540
2541 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 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 if unpack {
2656 emit!(self, Instruction::BuildTupleUnpack { size });
2657 } else {
2658 emit!(self, Instruction::BuildTuple { size });
2659 }
2660
2661 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 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 fn gather_elements(
2695 &mut self,
2696 before: u32,
2697 elements: &[located_ast::Expr],
2698 ) -> CompileResult<(u32, bool)> {
2699 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 let is_async_list_set_dict_comprehension = comprehension_type
2786 != ComprehensionType::Generator
2787 && (has_an_async_gen || element_contains_await) && prev_ctx.func == FunctionContext::AsyncFunction; let is_async_generator_comprehension = comprehension_type == ComprehensionType::Generator
2791 && (has_an_async_gen || element_contains_await);
2792
2793 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 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 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 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 if loop_labels.is_empty() {
2836 emit!(self, Instruction::LoadFast(arg0));
2838 } else {
2839 self.compile_expression(&generator.iter)?;
2841
2842 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 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 emit!(self, Instruction::Jump { target: loop_block });
2885
2886 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 self.emit_return_value();
2899
2900 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 self.emit_load_const(ConstantData::Code {
2912 code: Box::new(code),
2913 });
2914
2915 self.emit_load_const(ConstantData::Str {
2917 value: name.to_owned(),
2918 });
2919
2920 emit!(self, Instruction::MakeFunction(func_flags));
2922
2923 self.compile_expression(&generators[0].iter)?;
2925
2926 if has_an_async_gen {
2928 emit!(self, Instruction::GetAIter);
2929 } else {
2930 emit!(self, Instruction::GetIter);
2931 };
2932
2933 emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
2935 if is_async_list_set_dict_comprehension {
2936 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 "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 fn _emit(&mut self, instr: Instruction, arg: OpArg, target: ir::BlockIdx) {
2970 let location = self.current_source_location;
2971 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 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 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
3268trait 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}