1use crate::{
11 error::{CodegenError, CodegenErrorType},
12 IndexMap,
13};
14use bitflags::bitflags;
15use rustpython_ast::{self as ast, located::Located};
16use rustpython_parser_core::source_code::{LineNumber, SourceLocation};
17use std::{borrow::Cow, fmt};
18
19#[derive(Clone)]
21pub struct SymbolTable {
22 pub name: String,
24
25 pub typ: SymbolTableType,
27
28 pub line_number: u32,
30
31 pub is_nested: bool,
33
34 pub symbols: IndexMap<String, Symbol>,
36
37 pub sub_tables: Vec<SymbolTable>,
40}
41
42impl SymbolTable {
43 fn new(name: String, typ: SymbolTableType, line_number: u32, is_nested: bool) -> Self {
44 SymbolTable {
45 name,
46 typ,
47 line_number,
48 is_nested,
49 symbols: IndexMap::default(),
50 sub_tables: vec![],
51 }
52 }
53
54 pub fn scan_program(program: &[ast::located::Stmt]) -> SymbolTableResult<Self> {
55 let mut builder = SymbolTableBuilder::new();
56 builder.scan_statements(program)?;
57 builder.finish()
58 }
59
60 pub fn scan_expr(expr: &ast::located::Expr) -> SymbolTableResult<Self> {
61 let mut builder = SymbolTableBuilder::new();
62 builder.scan_expression(expr, ExpressionContext::Load)?;
63 builder.finish()
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum SymbolTableType {
69 Module,
70 Class,
71 Function,
72 Comprehension,
73 TypeParams,
74}
75
76impl fmt::Display for SymbolTableType {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 match self {
79 SymbolTableType::Module => write!(f, "module"),
80 SymbolTableType::Class => write!(f, "class"),
81 SymbolTableType::Function => write!(f, "function"),
82 SymbolTableType::Comprehension => write!(f, "comprehension"),
83 SymbolTableType::TypeParams => write!(f, "type parameter"),
84 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum SymbolScope {
99 Unknown,
100 Local,
101 GlobalExplicit,
102 GlobalImplicit,
103 Free,
104 Cell,
105}
106
107bitflags! {
108 #[derive(Copy, Clone, Debug, PartialEq)]
109 pub struct SymbolFlags: u16 {
110 const REFERENCED = 0x001;
111 const ASSIGNED = 0x002;
112 const PARAMETER = 0x004;
113 const ANNOTATED = 0x008;
114 const IMPORTED = 0x010;
115 const NONLOCAL = 0x020;
116 const ASSIGNED_IN_COMPREHENSION = 0x040;
119 const ITER = 0x080;
122 const FREE_CLASS = 0x100;
131 const BOUND = Self::ASSIGNED.bits() | Self::PARAMETER.bits() | Self::IMPORTED.bits() | Self::ITER.bits();
132 }
133}
134
135#[derive(Debug, Clone)]
138pub struct Symbol {
139 pub name: String,
140 pub scope: SymbolScope,
141 pub flags: SymbolFlags,
142}
143
144impl Symbol {
145 fn new(name: &str) -> Self {
146 Symbol {
147 name: name.to_owned(),
148 scope: SymbolScope::Unknown,
150 flags: SymbolFlags::empty(),
151 }
152 }
153
154 pub fn is_global(&self) -> bool {
155 matches!(
156 self.scope,
157 SymbolScope::GlobalExplicit | SymbolScope::GlobalImplicit
158 )
159 }
160
161 pub fn is_local(&self) -> bool {
162 matches!(self.scope, SymbolScope::Local | SymbolScope::Cell)
163 }
164
165 pub fn is_bound(&self) -> bool {
166 self.flags.intersects(SymbolFlags::BOUND)
167 }
168}
169
170#[derive(Debug)]
171pub struct SymbolTableError {
172 error: String,
173 location: Option<SourceLocation>,
174}
175
176impl SymbolTableError {
177 pub fn into_codegen_error(self, source_path: String) -> CodegenError {
178 CodegenError {
179 error: CodegenErrorType::SyntaxError(self.error),
180 location: self.location.map(|l| SourceLocation {
181 row: l.row,
182 column: l.column,
183 }),
184 source_path,
185 }
186 }
187}
188
189type SymbolTableResult<T = ()> = Result<T, SymbolTableError>;
190
191impl SymbolTable {
192 pub fn lookup(&self, name: &str) -> Option<&Symbol> {
193 self.symbols.get(name)
194 }
195}
196
197impl std::fmt::Debug for SymbolTable {
198 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
199 write!(
200 f,
201 "SymbolTable({:?} symbols, {:?} sub scopes)",
202 self.symbols.len(),
203 self.sub_tables.len()
204 )
205 }
206}
207
208fn analyze_symbol_table(symbol_table: &mut SymbolTable) -> SymbolTableResult {
212 let mut analyzer = SymbolTableAnalyzer::default();
213 analyzer.analyze_symbol_table(symbol_table)
214}
215
216type SymbolMap = IndexMap<String, Symbol>;
217
218mod stack {
219 use std::panic;
220 use std::ptr::NonNull;
221 pub struct StackStack<T> {
222 v: Vec<NonNull<T>>,
223 }
224 impl<T> Default for StackStack<T> {
225 fn default() -> Self {
226 Self { v: Vec::new() }
227 }
228 }
229 impl<T> StackStack<T> {
230 pub fn with_append<F, R>(&mut self, x: &mut T, f: F) -> R
233 where
234 F: FnOnce(&mut Self) -> R,
235 {
236 self.v.push(x.into());
237 let res = panic::catch_unwind(panic::AssertUnwindSafe(|| f(self)));
238 self.v.pop();
239 res.unwrap_or_else(|x| panic::resume_unwind(x))
240 }
241
242 pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> + '_ {
243 self.as_ref().iter().copied()
244 }
245 pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut T> + '_ {
246 self.as_mut().iter_mut().map(|x| &mut **x)
247 }
248 pub fn len(&self) -> usize {
255 self.v.len()
256 }
257 pub fn is_empty(&self) -> bool {
258 self.len() == 0
259 }
260
261 pub fn as_ref(&self) -> &[&T] {
262 unsafe { &*(self.v.as_slice() as *const [NonNull<T>] as *const [&T]) }
263 }
264
265 pub fn as_mut(&mut self) -> &mut [&mut T] {
266 unsafe { &mut *(self.v.as_mut_slice() as *mut [NonNull<T>] as *mut [&mut T]) }
267 }
268 }
269}
270use stack::StackStack;
271
272#[derive(Default)]
276#[repr(transparent)]
277struct SymbolTableAnalyzer {
278 tables: StackStack<(SymbolMap, SymbolTableType)>,
279}
280
281impl SymbolTableAnalyzer {
282 fn analyze_symbol_table(&mut self, symbol_table: &mut SymbolTable) -> SymbolTableResult {
283 let symbols = std::mem::take(&mut symbol_table.symbols);
284 let sub_tables = &mut *symbol_table.sub_tables;
285
286 let mut info = (symbols, symbol_table.typ);
287 self.tables.with_append(&mut info, |list| {
288 let inner_scope = unsafe { &mut *(list as *mut _ as *mut SymbolTableAnalyzer) };
289 for sub_table in sub_tables.iter_mut() {
291 inner_scope.analyze_symbol_table(sub_table)?;
292 }
293 Ok(())
294 })?;
295
296 symbol_table.symbols = info.0;
297
298 for symbol in symbol_table.symbols.values_mut() {
300 self.analyze_symbol(symbol, symbol_table.typ, sub_tables)?;
301 }
302 Ok(())
303 }
304
305 fn analyze_symbol(
306 &mut self,
307 symbol: &mut Symbol,
308 st_typ: SymbolTableType,
309 sub_tables: &[SymbolTable],
310 ) -> SymbolTableResult {
311 if symbol
312 .flags
313 .contains(SymbolFlags::ASSIGNED_IN_COMPREHENSION)
314 && st_typ == SymbolTableType::Comprehension
315 {
316 self.analyze_symbol_comprehension(symbol, 0)?
321 } else {
322 match symbol.scope {
323 SymbolScope::Free => {
324 if !self.tables.as_ref().is_empty() {
325 let scope_depth = self.tables.as_ref().len();
326 if scope_depth < 2
329 || self.found_in_outer_scope(&symbol.name) != Some(SymbolScope::Free)
330 {
331 return Err(SymbolTableError {
332 error: format!("no binding for nonlocal '{}' found", symbol.name),
333 location: None,
335 });
336 }
337 } else {
338 return Err(SymbolTableError {
339 error: format!(
340 "nonlocal {} defined at place without an enclosing scope",
341 symbol.name
342 ),
343 location: None,
345 });
346 }
347 }
348 SymbolScope::GlobalExplicit | SymbolScope::GlobalImplicit => {
349 }
351 SymbolScope::Local | SymbolScope::Cell => {
352 }
354 SymbolScope::Unknown => {
355 let scope = if symbol.is_bound() {
357 self.found_in_inner_scope(sub_tables, &symbol.name, st_typ)
358 .unwrap_or(SymbolScope::Local)
359 } else if let Some(scope) = self.found_in_outer_scope(&symbol.name) {
360 scope
361 } else if self.tables.is_empty() {
362 SymbolScope::Unknown
364 } else {
365 SymbolScope::GlobalImplicit
367 };
368 symbol.scope = scope;
369 }
370 }
371 }
372 Ok(())
373 }
374
375 fn found_in_outer_scope(&mut self, name: &str) -> Option<SymbolScope> {
376 let mut decl_depth = None;
377 for (i, (symbols, typ)) in self.tables.iter().rev().enumerate() {
378 if matches!(typ, SymbolTableType::Module)
379 || matches!(typ, SymbolTableType::Class if name != "__class__")
380 {
381 continue;
382 }
383 if let Some(sym) = symbols.get(name) {
384 match sym.scope {
385 SymbolScope::GlobalExplicit => return Some(SymbolScope::GlobalExplicit),
386 SymbolScope::GlobalImplicit => {}
387 _ => {
388 if sym.is_bound() {
389 decl_depth = Some(i);
390 break;
391 }
392 }
393 }
394 }
395 }
396
397 if let Some(decl_depth) = decl_depth {
398 for (table, typ) in self.tables.iter_mut().rev().take(decl_depth) {
401 if let SymbolTableType::Class = typ {
402 if let Some(free_class) = table.get_mut(name) {
403 free_class.flags.insert(SymbolFlags::FREE_CLASS)
404 } else {
405 let mut symbol = Symbol::new(name);
406 symbol.flags.insert(SymbolFlags::FREE_CLASS);
407 symbol.scope = SymbolScope::Free;
408 table.insert(name.to_owned(), symbol);
409 }
410 } else if !table.contains_key(name) {
411 let mut symbol = Symbol::new(name);
412 symbol.scope = SymbolScope::Free;
413 table.insert(name.to_owned(), symbol);
415 }
416 }
417 }
418
419 decl_depth.map(|_| SymbolScope::Free)
420 }
421
422 fn found_in_inner_scope(
423 &self,
424 sub_tables: &[SymbolTable],
425 name: &str,
426 st_typ: SymbolTableType,
427 ) -> Option<SymbolScope> {
428 sub_tables.iter().find_map(|st| {
429 let sym = st.symbols.get(name)?;
430 if sym.scope == SymbolScope::Free || sym.flags.contains(SymbolFlags::FREE_CLASS) {
431 if st_typ == SymbolTableType::Class && name != "__class__" {
432 None
433 } else {
434 Some(SymbolScope::Cell)
435 }
436 } else if sym.scope == SymbolScope::GlobalExplicit && self.tables.is_empty() {
437 Some(SymbolScope::GlobalExplicit)
440 } else {
441 None
442 }
443 })
444 }
445
446 fn analyze_symbol_comprehension(
450 &mut self,
451 symbol: &mut Symbol,
452 parent_offset: usize,
453 ) -> SymbolTableResult {
454 let last = self.tables.iter_mut().rev().nth(parent_offset).unwrap();
456 let symbols = &mut last.0;
457 let table_type = last.1;
458
459 if symbol.flags.contains(SymbolFlags::ITER) {
461 return Err(SymbolTableError {
462 error: format!(
463 "assignment expression cannot rebind comprehension iteration variable {}",
464 symbol.name
465 ),
466 location: None,
468 });
469 }
470
471 match table_type {
472 SymbolTableType::Module => {
473 symbol.scope = SymbolScope::GlobalImplicit;
474 }
475 SymbolTableType::Class => {
476 return Err(SymbolTableError {
478 error: "assignment expression within a comprehension cannot be used in a class body".to_string(),
479 location: None,
481 });
482 }
483 SymbolTableType::Function => {
484 if let Some(parent_symbol) = symbols.get_mut(&symbol.name) {
485 if let SymbolScope::Unknown = parent_symbol.scope {
486 parent_symbol.flags.insert(SymbolFlags::ASSIGNED);
488 }
489
490 symbol.scope = if parent_symbol.is_global() {
491 parent_symbol.scope
492 } else {
493 SymbolScope::Free
494 };
495 } else {
496 let mut cloned_sym = symbol.clone();
497 cloned_sym.scope = SymbolScope::Cell;
498 last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
499 }
500 }
501 SymbolTableType::Comprehension => {
502 match symbols.get_mut(&symbol.name) {
504 Some(parent_symbol) => {
505 if parent_symbol.flags.contains(SymbolFlags::ITER) {
507 return Err(SymbolTableError {
508 error: format!("assignment expression cannot rebind comprehension iteration variable {}", symbol.name),
509 location: None,
510 });
511 }
512
513 parent_symbol.flags.insert(SymbolFlags::ASSIGNED); }
516 None => {
517 let mut cloned_sym = symbol.clone();
522 cloned_sym.scope = SymbolScope::Free;
523 last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
524 }
525 }
526
527 self.analyze_symbol_comprehension(symbol, parent_offset + 1)?;
528 }
529 SymbolTableType::TypeParams => {
530 todo!("analyze symbol comprehension for type params");
531 }
532 }
533 Ok(())
534 }
535}
536
537#[derive(Debug, Clone)]
538enum SymbolUsage {
539 Global,
540 Nonlocal,
541 Used,
542 Assigned,
543 Imported,
544 AnnotationAssigned,
545 Parameter,
546 AnnotationParameter,
547 AssignedNamedExprInComprehension,
548 Iter,
549}
550
551struct SymbolTableBuilder {
552 class_name: Option<String>,
553 tables: Vec<SymbolTable>,
555 future_annotations: bool,
556}
557
558#[derive(Copy, Clone, PartialEq)]
563enum ExpressionContext {
564 Load,
565 Store,
566 Delete,
567 Iter,
568 IterDefinitionExp,
569}
570
571impl SymbolTableBuilder {
572 fn new() -> Self {
573 let mut this = Self {
574 class_name: None,
575 tables: vec![],
576 future_annotations: false,
577 };
578 this.enter_scope("top", SymbolTableType::Module, 0);
579 this
580 }
581}
582
583impl SymbolTableBuilder {
584 fn finish(mut self) -> Result<SymbolTable, SymbolTableError> {
585 assert_eq!(self.tables.len(), 1);
586 let mut symbol_table = self.tables.pop().unwrap();
587 analyze_symbol_table(&mut symbol_table)?;
588 Ok(symbol_table)
589 }
590
591 fn enter_scope(&mut self, name: &str, typ: SymbolTableType, line_number: u32) {
592 let is_nested = self
593 .tables
594 .last()
595 .map(|table| table.is_nested || table.typ == SymbolTableType::Function)
596 .unwrap_or(false);
597 let table = SymbolTable::new(name.to_owned(), typ, line_number, is_nested);
598 self.tables.push(table);
599 }
600
601 fn leave_scope(&mut self) {
603 let table = self.tables.pop().unwrap();
604 self.tables.last_mut().unwrap().sub_tables.push(table);
605 }
606
607 fn scan_statements(&mut self, statements: &[ast::located::Stmt]) -> SymbolTableResult {
608 for statement in statements {
609 self.scan_statement(statement)?;
610 }
611 Ok(())
612 }
613
614 fn scan_parameters(
615 &mut self,
616 parameters: &[ast::located::ArgWithDefault],
617 ) -> SymbolTableResult {
618 for parameter in parameters {
619 let usage = if parameter.def.annotation.is_some() {
620 SymbolUsage::AnnotationParameter
621 } else {
622 SymbolUsage::Parameter
623 };
624 self.register_name(parameter.def.arg.as_str(), usage, parameter.def.location())?;
625 }
626 Ok(())
627 }
628
629 fn scan_parameter(&mut self, parameter: &ast::located::Arg) -> SymbolTableResult {
630 let usage = if parameter.annotation.is_some() {
631 SymbolUsage::AnnotationParameter
632 } else {
633 SymbolUsage::Parameter
634 };
635 self.register_name(parameter.arg.as_str(), usage, parameter.location())
636 }
637
638 fn scan_annotation(&mut self, annotation: &ast::located::Expr) -> SymbolTableResult {
639 if self.future_annotations {
640 Ok(())
641 } else {
642 self.scan_expression(annotation, ExpressionContext::Load)
643 }
644 }
645
646 fn scan_statement(&mut self, statement: &ast::located::Stmt) -> SymbolTableResult {
647 use ast::located::*;
648 if let Stmt::ImportFrom(StmtImportFrom { module, names, .. }) = &statement {
649 if module.as_ref().map(|id| id.as_str()) == Some("__future__") {
650 for feature in names {
651 if &feature.name == "annotations" {
652 self.future_annotations = true;
653 }
654 }
655 }
656 }
657 match &statement {
658 Stmt::Global(StmtGlobal { names, range }) => {
659 for name in names {
660 self.register_name(name.as_str(), SymbolUsage::Global, range.start)?;
661 }
662 }
663 Stmt::Nonlocal(StmtNonlocal { names, range }) => {
664 for name in names {
665 self.register_name(name.as_str(), SymbolUsage::Nonlocal, range.start)?;
666 }
667 }
668 Stmt::FunctionDef(StmtFunctionDef {
669 name,
670 body,
671 args,
672 decorator_list,
673 type_params,
674 returns,
675 range,
676 ..
677 })
678 | Stmt::AsyncFunctionDef(StmtAsyncFunctionDef {
679 name,
680 body,
681 args,
682 decorator_list,
683 type_params,
684 returns,
685 range,
686 ..
687 }) => {
688 self.scan_expressions(decorator_list, ExpressionContext::Load)?;
689 self.register_name(name.as_str(), SymbolUsage::Assigned, range.start)?;
690 if let Some(expression) = returns {
691 self.scan_annotation(expression)?;
692 }
693 if !type_params.is_empty() {
694 self.enter_scope(
695 &format!("<generic parameters of {}>", name.as_str()),
696 SymbolTableType::TypeParams,
697 range.start.row.get(),
698 );
699 self.scan_type_params(type_params)?;
700 }
701 self.enter_function(name.as_str(), args, range.start.row)?;
702 self.scan_statements(body)?;
703 self.leave_scope();
704 if !type_params.is_empty() {
705 self.leave_scope();
706 }
707 }
708 Stmt::ClassDef(StmtClassDef {
709 name,
710 body,
711 bases,
712 keywords,
713 decorator_list,
714 type_params,
715 range,
716 }) => {
717 if !type_params.is_empty() {
718 self.enter_scope(
719 &format!("<generic parameters of {}>", name.as_str()),
720 SymbolTableType::TypeParams,
721 range.start.row.get(),
722 );
723 self.scan_type_params(type_params)?;
724 }
725 self.enter_scope(name.as_str(), SymbolTableType::Class, range.start.row.get());
726 let prev_class = std::mem::replace(&mut self.class_name, Some(name.to_string()));
727 self.register_name("__module__", SymbolUsage::Assigned, range.start)?;
728 self.register_name("__qualname__", SymbolUsage::Assigned, range.start)?;
729 self.register_name("__doc__", SymbolUsage::Assigned, range.start)?;
730 self.register_name("__class__", SymbolUsage::Assigned, range.start)?;
731 self.scan_statements(body)?;
732 self.leave_scope();
733 self.class_name = prev_class;
734 self.scan_expressions(bases, ExpressionContext::Load)?;
735 for keyword in keywords {
736 self.scan_expression(&keyword.value, ExpressionContext::Load)?;
737 }
738 if !type_params.is_empty() {
739 self.leave_scope();
740 }
741 self.scan_expressions(decorator_list, ExpressionContext::Load)?;
742 self.register_name(name.as_str(), SymbolUsage::Assigned, range.start)?;
743 }
744 Stmt::Expr(StmtExpr { value, .. }) => {
745 self.scan_expression(value, ExpressionContext::Load)?
746 }
747 Stmt::If(StmtIf {
748 test, body, orelse, ..
749 }) => {
750 self.scan_expression(test, ExpressionContext::Load)?;
751 self.scan_statements(body)?;
752 self.scan_statements(orelse)?;
753 }
754 Stmt::For(StmtFor {
755 target,
756 iter,
757 body,
758 orelse,
759 ..
760 })
761 | Stmt::AsyncFor(StmtAsyncFor {
762 target,
763 iter,
764 body,
765 orelse,
766 ..
767 }) => {
768 self.scan_expression(target, ExpressionContext::Store)?;
769 self.scan_expression(iter, ExpressionContext::Load)?;
770 self.scan_statements(body)?;
771 self.scan_statements(orelse)?;
772 }
773 Stmt::While(StmtWhile {
774 test, body, orelse, ..
775 }) => {
776 self.scan_expression(test, ExpressionContext::Load)?;
777 self.scan_statements(body)?;
778 self.scan_statements(orelse)?;
779 }
780 Stmt::Break(_) | Stmt::Continue(_) | Stmt::Pass(_) => {
781 }
783 Stmt::Import(StmtImport { names, range })
784 | Stmt::ImportFrom(StmtImportFrom { names, range, .. }) => {
785 for name in names {
786 if let Some(alias) = &name.asname {
787 self.register_name(alias.as_str(), SymbolUsage::Imported, range.start)?;
789 } else {
790 self.register_name(
792 name.name.split('.').next().unwrap(),
793 SymbolUsage::Imported,
794 range.start,
795 )?;
796 }
797 }
798 }
799 Stmt::Return(StmtReturn { value, .. }) => {
800 if let Some(expression) = value {
801 self.scan_expression(expression, ExpressionContext::Load)?;
802 }
803 }
804 Stmt::Assert(StmtAssert { test, msg, .. }) => {
805 self.scan_expression(test, ExpressionContext::Load)?;
806 if let Some(expression) = msg {
807 self.scan_expression(expression, ExpressionContext::Load)?;
808 }
809 }
810 Stmt::Delete(StmtDelete { targets, .. }) => {
811 self.scan_expressions(targets, ExpressionContext::Delete)?;
812 }
813 Stmt::Assign(StmtAssign { targets, value, .. }) => {
814 self.scan_expressions(targets, ExpressionContext::Store)?;
815 self.scan_expression(value, ExpressionContext::Load)?;
816 }
817 Stmt::AugAssign(StmtAugAssign { target, value, .. }) => {
818 self.scan_expression(target, ExpressionContext::Store)?;
819 self.scan_expression(value, ExpressionContext::Load)?;
820 }
821 Stmt::AnnAssign(StmtAnnAssign {
822 target,
823 annotation,
824 value,
825 simple,
826 range,
827 }) => {
828 match &**target {
830 Expr::Name(ast::ExprName { id, .. }) if *simple => {
831 self.register_name(
832 id.as_str(),
833 SymbolUsage::AnnotationAssigned,
834 range.start,
835 )?;
836 }
837 _ => {
838 self.scan_expression(target, ExpressionContext::Store)?;
839 }
840 }
841 self.scan_annotation(annotation)?;
842 if let Some(value) = value {
843 self.scan_expression(value, ExpressionContext::Load)?;
844 }
845 }
846 Stmt::With(StmtWith { items, body, .. })
847 | Stmt::AsyncWith(StmtAsyncWith { items, body, .. }) => {
848 for item in items {
849 self.scan_expression(&item.context_expr, ExpressionContext::Load)?;
850 if let Some(expression) = &item.optional_vars {
851 self.scan_expression(expression, ExpressionContext::Store)?;
852 }
853 }
854 self.scan_statements(body)?;
855 }
856 Stmt::Try(StmtTry {
857 body,
858 handlers,
859 orelse,
860 finalbody,
861 range,
862 })
863 | Stmt::TryStar(StmtTryStar {
864 body,
865 handlers,
866 orelse,
867 finalbody,
868 range,
869 }) => {
870 self.scan_statements(body)?;
871 for handler in handlers {
872 let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
873 type_,
874 name,
875 body,
876 ..
877 }) = &handler;
878 if let Some(expression) = type_ {
879 self.scan_expression(expression, ExpressionContext::Load)?;
880 }
881 if let Some(name) = name {
882 self.register_name(name.as_str(), SymbolUsage::Assigned, range.start)?;
883 }
884 self.scan_statements(body)?;
885 }
886 self.scan_statements(orelse)?;
887 self.scan_statements(finalbody)?;
888 }
889 Stmt::Match(StmtMatch { subject, .. }) => {
890 return Err(SymbolTableError {
891 error: "match expression is not implemented yet".to_owned(),
892 location: Some(subject.location()),
893 });
894 }
895 Stmt::Raise(StmtRaise { exc, cause, .. }) => {
896 if let Some(expression) = exc {
897 self.scan_expression(expression, ExpressionContext::Load)?;
898 }
899 if let Some(expression) = cause {
900 self.scan_expression(expression, ExpressionContext::Load)?;
901 }
902 }
903 Stmt::TypeAlias(StmtTypeAlias {
904 name,
905 value,
906 type_params,
907 range,
908 }) => {
909 if !type_params.is_empty() {
910 self.enter_scope(
911 &name.to_string(),
912 SymbolTableType::TypeParams,
913 range.start.row.get(),
914 );
915 self.scan_type_params(type_params)?;
916 self.scan_expression(value, ExpressionContext::Load)?;
917 self.leave_scope();
918 } else {
919 self.scan_expression(value, ExpressionContext::Load)?;
920 }
921 self.scan_expression(name, ExpressionContext::Store)?;
922 }
923 }
924 Ok(())
925 }
926
927 fn scan_expressions(
928 &mut self,
929 expressions: &[ast::located::Expr],
930 context: ExpressionContext,
931 ) -> SymbolTableResult {
932 for expression in expressions {
933 self.scan_expression(expression, context)?;
934 }
935 Ok(())
936 }
937
938 fn scan_expression(
939 &mut self,
940 expression: &ast::located::Expr,
941 context: ExpressionContext,
942 ) -> SymbolTableResult {
943 use ast::located::*;
944 match expression {
945 Expr::BinOp(ExprBinOp {
946 left,
947 right,
948 range: _,
949 ..
950 }) => {
951 self.scan_expression(left, context)?;
952 self.scan_expression(right, context)?;
953 }
954 Expr::BoolOp(ExprBoolOp {
955 values, range: _, ..
956 }) => {
957 self.scan_expressions(values, context)?;
958 }
959 Expr::Compare(ExprCompare {
960 left,
961 comparators,
962 range: _,
963 ..
964 }) => {
965 self.scan_expression(left, context)?;
966 self.scan_expressions(comparators, context)?;
967 }
968 Expr::Subscript(ExprSubscript {
969 value,
970 slice,
971 range: _,
972 ..
973 }) => {
974 self.scan_expression(value, ExpressionContext::Load)?;
975 self.scan_expression(slice, ExpressionContext::Load)?;
976 }
977 Expr::Attribute(ExprAttribute {
978 value, range: _, ..
979 }) => {
980 self.scan_expression(value, ExpressionContext::Load)?;
981 }
982 Expr::Dict(ExprDict {
983 keys,
984 values,
985 range: _,
986 }) => {
987 for (key, value) in keys.iter().zip(values.iter()) {
988 if let Some(key) = key {
989 self.scan_expression(key, context)?;
990 }
991 self.scan_expression(value, context)?;
992 }
993 }
994 Expr::Await(ExprAwait { value, range: _ }) => {
995 self.scan_expression(value, context)?;
996 }
997 Expr::Yield(ExprYield { value, range: _ }) => {
998 if let Some(expression) = value {
999 self.scan_expression(expression, context)?;
1000 }
1001 }
1002 Expr::YieldFrom(ExprYieldFrom { value, range: _ }) => {
1003 self.scan_expression(value, context)?;
1004 }
1005 Expr::UnaryOp(ExprUnaryOp {
1006 operand, range: _, ..
1007 }) => {
1008 self.scan_expression(operand, context)?;
1009 }
1010 Expr::Constant(ExprConstant { range: _, .. }) => {}
1011 Expr::Starred(ExprStarred {
1012 value, range: _, ..
1013 }) => {
1014 self.scan_expression(value, context)?;
1015 }
1016 Expr::Tuple(ExprTuple { elts, range: _, .. })
1017 | Expr::Set(ExprSet { elts, range: _, .. })
1018 | Expr::List(ExprList { elts, range: _, .. }) => {
1019 self.scan_expressions(elts, context)?;
1020 }
1021 Expr::Slice(ExprSlice {
1022 lower,
1023 upper,
1024 step,
1025 range: _,
1026 }) => {
1027 if let Some(lower) = lower {
1028 self.scan_expression(lower, context)?;
1029 }
1030 if let Some(upper) = upper {
1031 self.scan_expression(upper, context)?;
1032 }
1033 if let Some(step) = step {
1034 self.scan_expression(step, context)?;
1035 }
1036 }
1037 Expr::GeneratorExp(ExprGeneratorExp {
1038 elt,
1039 generators,
1040 range,
1041 }) => {
1042 self.scan_comprehension("genexpr", elt, None, generators, range.start)?;
1043 }
1044 Expr::ListComp(ExprListComp {
1045 elt,
1046 generators,
1047 range,
1048 }) => {
1049 self.scan_comprehension("genexpr", elt, None, generators, range.start)?;
1050 }
1051 Expr::SetComp(ExprSetComp {
1052 elt,
1053 generators,
1054 range,
1055 }) => {
1056 self.scan_comprehension("genexpr", elt, None, generators, range.start)?;
1057 }
1058 Expr::DictComp(ExprDictComp {
1059 key,
1060 value,
1061 generators,
1062 range,
1063 }) => {
1064 self.scan_comprehension("genexpr", key, Some(value), generators, range.start)?;
1065 }
1066 Expr::Call(ExprCall {
1067 func,
1068 args,
1069 keywords,
1070 range: _,
1071 }) => {
1072 match context {
1073 ExpressionContext::IterDefinitionExp => {
1074 self.scan_expression(func, ExpressionContext::IterDefinitionExp)?;
1075 }
1076 _ => {
1077 self.scan_expression(func, ExpressionContext::Load)?;
1078 }
1079 }
1080
1081 self.scan_expressions(args, ExpressionContext::Load)?;
1082 for keyword in keywords {
1083 self.scan_expression(&keyword.value, ExpressionContext::Load)?;
1084 }
1085 }
1086 Expr::FormattedValue(ExprFormattedValue {
1087 value,
1088 format_spec,
1089 range: _,
1090 ..
1091 }) => {
1092 self.scan_expression(value, ExpressionContext::Load)?;
1093 if let Some(spec) = format_spec {
1094 self.scan_expression(spec, ExpressionContext::Load)?;
1095 }
1096 }
1097 Expr::JoinedStr(ExprJoinedStr { values, range: _ }) => {
1098 for value in values {
1099 self.scan_expression(value, ExpressionContext::Load)?;
1100 }
1101 }
1102 Expr::Name(ExprName { id, range, .. }) => {
1103 let id = id.as_str();
1104 match context {
1106 ExpressionContext::Delete => {
1107 self.register_name(id, SymbolUsage::Assigned, range.start)?;
1108 self.register_name(id, SymbolUsage::Used, range.start)?;
1109 }
1110 ExpressionContext::Load | ExpressionContext::IterDefinitionExp => {
1111 self.register_name(id, SymbolUsage::Used, range.start)?;
1112 }
1113 ExpressionContext::Store => {
1114 self.register_name(id, SymbolUsage::Assigned, range.start)?;
1115 }
1116 ExpressionContext::Iter => {
1117 self.register_name(id, SymbolUsage::Iter, range.start)?;
1118 }
1119 }
1120 if context == ExpressionContext::Load
1123 && self.tables.last().unwrap().typ == SymbolTableType::Function
1124 && id == "super"
1125 {
1126 self.register_name("__class__", SymbolUsage::Used, range.start)?;
1127 }
1128 }
1129 Expr::Lambda(ExprLambda {
1130 args,
1131 body,
1132 range: _,
1133 }) => {
1134 self.enter_function("lambda", args, expression.location().row)?;
1135 match context {
1136 ExpressionContext::IterDefinitionExp => {
1137 self.scan_expression(body, ExpressionContext::IterDefinitionExp)?;
1138 }
1139 _ => {
1140 self.scan_expression(body, ExpressionContext::Load)?;
1141 }
1142 }
1143 self.leave_scope();
1144 }
1145 Expr::IfExp(ExprIfExp {
1146 test,
1147 body,
1148 orelse,
1149 range: _,
1150 }) => {
1151 self.scan_expression(test, ExpressionContext::Load)?;
1152 self.scan_expression(body, ExpressionContext::Load)?;
1153 self.scan_expression(orelse, ExpressionContext::Load)?;
1154 }
1155
1156 Expr::NamedExpr(ExprNamedExpr {
1157 target,
1158 value,
1159 range,
1160 }) => {
1161 if let ExpressionContext::IterDefinitionExp = context {
1164 return Err(SymbolTableError {
1165 error: "assignment expression cannot be used in a comprehension iterable expression".to_string(),
1166 location: Some(target.location()),
1167 });
1168 }
1169
1170 self.scan_expression(value, ExpressionContext::Load)?;
1171
1172 if let Expr::Name(ExprName { id, .. }) = &**target {
1177 let id = id.as_str();
1178 let table = self.tables.last().unwrap();
1179 if table.typ == SymbolTableType::Comprehension {
1180 self.register_name(
1181 id,
1182 SymbolUsage::AssignedNamedExprInComprehension,
1183 range.start,
1184 )?;
1185 } else {
1186 self.register_name(id, SymbolUsage::Assigned, range.start)?;
1190 }
1191 } else {
1192 self.scan_expression(target, ExpressionContext::Store)?;
1193 }
1194 }
1195 }
1196 Ok(())
1197 }
1198
1199 fn scan_comprehension(
1200 &mut self,
1201 scope_name: &str,
1202 elt1: &ast::located::Expr,
1203 elt2: Option<&ast::located::Expr>,
1204 generators: &[ast::located::Comprehension],
1205 location: SourceLocation,
1206 ) -> SymbolTableResult {
1207 self.enter_scope(
1209 scope_name,
1210 SymbolTableType::Comprehension,
1211 location.row.get(),
1212 );
1213
1214 self.register_name(".0", SymbolUsage::Parameter, location)?;
1216
1217 self.scan_expression(elt1, ExpressionContext::Load)?;
1218 if let Some(elt2) = elt2 {
1219 self.scan_expression(elt2, ExpressionContext::Load)?;
1220 }
1221
1222 let mut is_first_generator = true;
1223 for generator in generators {
1224 self.scan_expression(&generator.target, ExpressionContext::Iter)?;
1225 if is_first_generator {
1226 is_first_generator = false;
1227 } else {
1228 self.scan_expression(&generator.iter, ExpressionContext::IterDefinitionExp)?;
1229 }
1230
1231 for if_expr in &generator.ifs {
1232 self.scan_expression(if_expr, ExpressionContext::Load)?;
1233 }
1234 }
1235
1236 self.leave_scope();
1237
1238 assert!(!generators.is_empty());
1240 self.scan_expression(&generators[0].iter, ExpressionContext::IterDefinitionExp)?;
1241
1242 Ok(())
1243 }
1244
1245 fn scan_type_params(&mut self, type_params: &[ast::located::TypeParam]) -> SymbolTableResult {
1246 for type_param in type_params {
1247 match type_param {
1248 ast::located::TypeParam::TypeVar(ast::TypeParamTypeVar {
1249 name,
1250 bound,
1251 range: type_var_range,
1252 }) => {
1253 self.register_name(name.as_str(), SymbolUsage::Assigned, type_var_range.start)?;
1254 if let Some(binding) = bound {
1255 self.scan_expression(binding, ExpressionContext::Load)?;
1256 }
1257 }
1258 ast::located::TypeParam::ParamSpec(_) => todo!(),
1259 ast::located::TypeParam::TypeVarTuple(_) => todo!(),
1260 }
1261 }
1262 Ok(())
1263 }
1264
1265 fn enter_function(
1266 &mut self,
1267 name: &str,
1268 args: &ast::located::Arguments,
1269 line_number: LineNumber,
1270 ) -> SymbolTableResult {
1271 for default in args
1273 .posonlyargs
1274 .iter()
1275 .chain(args.args.iter())
1276 .chain(args.kwonlyargs.iter())
1277 .filter_map(|arg| arg.default.as_ref())
1278 {
1279 self.scan_expression(default, ExpressionContext::Load)?; }
1281
1282 for annotation in args
1284 .posonlyargs
1285 .iter()
1286 .chain(args.args.iter())
1287 .chain(args.kwonlyargs.iter())
1288 .filter_map(|arg| arg.def.annotation.as_ref())
1289 {
1290 self.scan_annotation(annotation)?;
1291 }
1292 if let Some(annotation) = args.vararg.as_ref().and_then(|arg| arg.annotation.as_ref()) {
1293 self.scan_annotation(annotation)?;
1294 }
1295 if let Some(annotation) = args.kwarg.as_ref().and_then(|arg| arg.annotation.as_ref()) {
1296 self.scan_annotation(annotation)?;
1297 }
1298
1299 self.enter_scope(name, SymbolTableType::Function, line_number.get());
1300
1301 self.scan_parameters(&args.posonlyargs)?;
1303 self.scan_parameters(&args.args)?;
1304 self.scan_parameters(&args.kwonlyargs)?;
1305 if let Some(name) = &args.vararg {
1306 self.scan_parameter(name)?;
1307 }
1308 if let Some(name) = &args.kwarg {
1309 self.scan_parameter(name)?;
1310 }
1311 Ok(())
1312 }
1313
1314 fn register_name(
1315 &mut self,
1316 name: &str,
1317 role: SymbolUsage,
1318 location: SourceLocation,
1319 ) -> SymbolTableResult {
1320 let location = Some(location);
1321 let scope_depth = self.tables.len();
1322 let table = self.tables.last_mut().unwrap();
1323
1324 let name = mangle_name(self.class_name.as_deref(), name);
1325 let symbol = if let Some(symbol) = table.symbols.get_mut(name.as_ref()) {
1327 let flags = &symbol.flags;
1328 match role {
1330 SymbolUsage::Global if !symbol.is_global() => {
1331 if flags.contains(SymbolFlags::PARAMETER) {
1332 return Err(SymbolTableError {
1333 error: format!("name '{name}' is parameter and global"),
1334 location,
1335 });
1336 }
1337 if flags.contains(SymbolFlags::REFERENCED) {
1338 return Err(SymbolTableError {
1339 error: format!("name '{name}' is used prior to global declaration"),
1340 location,
1341 });
1342 }
1343 if flags.contains(SymbolFlags::ANNOTATED) {
1344 return Err(SymbolTableError {
1345 error: format!("annotated name '{name}' can't be global"),
1346 location,
1347 });
1348 }
1349 if flags.contains(SymbolFlags::ASSIGNED) {
1350 return Err(SymbolTableError {
1351 error: format!(
1352 "name '{name}' is assigned to before global declaration"
1353 ),
1354 location,
1355 });
1356 }
1357 }
1358 SymbolUsage::Nonlocal => {
1359 if flags.contains(SymbolFlags::PARAMETER) {
1360 return Err(SymbolTableError {
1361 error: format!("name '{name}' is parameter and nonlocal"),
1362 location,
1363 });
1364 }
1365 if flags.contains(SymbolFlags::REFERENCED) {
1366 return Err(SymbolTableError {
1367 error: format!("name '{name}' is used prior to nonlocal declaration"),
1368 location,
1369 });
1370 }
1371 if flags.contains(SymbolFlags::ANNOTATED) {
1372 return Err(SymbolTableError {
1373 error: format!("annotated name '{name}' can't be nonlocal"),
1374 location,
1375 });
1376 }
1377 if flags.contains(SymbolFlags::ASSIGNED) {
1378 return Err(SymbolTableError {
1379 error: format!(
1380 "name '{name}' is assigned to before nonlocal declaration"
1381 ),
1382 location,
1383 });
1384 }
1385 }
1386 _ => {
1387 }
1389 }
1390 symbol
1391 } else {
1392 match role {
1395 SymbolUsage::Nonlocal if scope_depth < 2 => {
1396 return Err(SymbolTableError {
1397 error: format!("cannot define nonlocal '{name}' at top level."),
1398 location,
1399 })
1400 }
1401 _ => {
1402 }
1404 }
1405 let symbol = Symbol::new(name.as_ref());
1407 table.symbols.entry(name.into_owned()).or_insert(symbol)
1408 };
1409
1410 let flags = &mut symbol.flags;
1412 match role {
1413 SymbolUsage::Nonlocal => {
1414 symbol.scope = SymbolScope::Free;
1415 flags.insert(SymbolFlags::NONLOCAL);
1416 }
1417 SymbolUsage::Imported => {
1418 flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::IMPORTED);
1419 }
1420 SymbolUsage::Parameter => {
1421 flags.insert(SymbolFlags::PARAMETER);
1422 }
1423 SymbolUsage::AnnotationParameter => {
1424 flags.insert(SymbolFlags::PARAMETER | SymbolFlags::ANNOTATED);
1425 }
1426 SymbolUsage::AnnotationAssigned => {
1427 flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::ANNOTATED);
1428 }
1429 SymbolUsage::Assigned => {
1430 flags.insert(SymbolFlags::ASSIGNED);
1431 }
1432 SymbolUsage::AssignedNamedExprInComprehension => {
1433 flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::ASSIGNED_IN_COMPREHENSION);
1434 }
1435 SymbolUsage::Global => {
1436 symbol.scope = SymbolScope::GlobalExplicit;
1437 }
1438 SymbolUsage::Used => {
1439 flags.insert(SymbolFlags::REFERENCED);
1440 }
1441 SymbolUsage::Iter => {
1442 flags.insert(SymbolFlags::ITER);
1443 }
1444 }
1445
1446 if flags.contains(SymbolFlags::ITER | SymbolFlags::ASSIGNED)
1449 {
1451 return Err(SymbolTableError {
1452 error:
1453 "assignment expression cannot be used in a comprehension iterable expression"
1454 .to_string(),
1455 location,
1456 });
1457 }
1458 Ok(())
1459 }
1460}
1461
1462pub(crate) fn mangle_name<'a>(class_name: Option<&str>, name: &'a str) -> Cow<'a, str> {
1463 let class_name = match class_name {
1464 Some(n) => n,
1465 None => return name.into(),
1466 };
1467 if !name.starts_with("__") || name.ends_with("__") || name.contains('.') {
1468 return name.into();
1469 }
1470 let class_name = class_name.strip_prefix(|c| c == '_').unwrap_or(class_name);
1472 let mut ret = String::with_capacity(1 + class_name.len() + name.len());
1473 ret.push('_');
1474 ret.push_str(class_name);
1475 ret.push_str(name);
1476 ret.into()
1477}