fn analyze_symbol_comprehension(
        &mut self,
        symbol: &mut Symbol,
        parent_offset: usize,
    ) -> SymbolTableResult {
        // when this is called, we expect to be in the direct parent scope of the scope that contains 'symbol'
        let last = self.tables.iter_mut().rev().nth(parent_offset).unwrap();
        let symbols = &mut last.0;
        let table_type = last.1;

        // it is not allowed to use an iterator variable as assignee in a named expression
        if symbol.is_iter {
            return Err(SymbolTableError {
                error: format!(
                    "assignment expression cannot rebind comprehension iteration variable {}",
                    symbol.name
                ),
                // TODO: accurate location info, somehow
                location: Location::default(),
            });
        }

        match table_type {
            SymbolTableType::Module => {
                symbol.scope = SymbolScope::GlobalImplicit;
            }
            SymbolTableType::Class => {
                // named expressions are forbidden in comprehensions on class scope
                return Err(SymbolTableError {
                    error: "assignment expression within a comprehension cannot be used in a class body".to_string(),
                    // TODO: accurate location info, somehow
                    location: Location::default(),
                });
            }
            SymbolTableType::Function => {
                if let Some(parent_symbol) = symbols.get_mut(&symbol.name) {
                    if let SymbolScope::Unknown = parent_symbol.scope {
                        // this information is new, as the assignment is done in inner scope
                        parent_symbol.is_assigned = true;
                    }

                    symbol.scope = if parent_symbol.is_global() {
                        parent_symbol.scope
                    } else {
                        SymbolScope::Free
                    };
                } else {
                    let mut cloned_sym = symbol.clone();
                    cloned_sym.scope = SymbolScope::Local;
                    last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
                }
            }
            SymbolTableType::Comprehension => {
                // TODO check for conflicts - requires more context information about variables
                match symbols.get_mut(&symbol.name) {
                    Some(parent_symbol) => {
                        // check if assignee is an iterator in top scope
                        if parent_symbol.is_iter {
                            return Err(SymbolTableError {
                                error: format!("assignment expression cannot rebind comprehension iteration variable {}", symbol.name),
                                // TODO: accurate location info, somehow
                                location: Location::default(),
                            });
                        }

                        // we synthesize the assignment to the symbol from inner scope
                        parent_symbol.is_assigned = true; // more checks are required
                    }
                    None => {
                        // extend the scope of the inner symbol
                        // as we are in a nested comprehension, we expect that the symbol is needed
                        // outside, too, and set it therefore to non-local scope. I.e., we expect to
                        // find a definition on a higher level
                        let mut cloned_sym = symbol.clone();
                        cloned_sym.scope = SymbolScope::Free;
                        last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
                    }
                }

                self.analyze_symbol_comprehension(symbol, parent_offset + 1)?;
            }
        }
        Ok(())
    }
// Implements the symbol analysis and scope extension for names
// assigned by a named expression in a comprehension. See:
// https://github.com/python/cpython/blob/7b78e7f9fd77bb3280ee39fb74b86772a7d46a70/Python/symtable.c#L1435
Implements the symbol analysis and scope extension for names
assigned by a named expression in a comprehension.
Implements the symbol analysis and scope extension for names assigned by a named expression in a comprehension .
fn analyze_symbol_comprehension(
        &mut self,
        symbol: &mut Symbol,
        parent_offset: usize,
    ) -> SymbolTableResult {
        // when this is called, we expect to be in the direct parent scope of the scope that contains 'symbol'
        let last = self.tables.iter_mut().rev().nth(parent_offset).unwrap();
        let symbols = &mut last.0;
        let table_type = last.1;
        // it is not allowed to use an iterator variable as assignee in a named expression
        if symbol.is_iter {
            return Err(SymbolTableError {
                error: format!(
                    "assignment expression cannot rebind comprehension iteration variable {}",
                    symbol.name
                ),
                // TODO: accurate location info, somehow
                location: Location::default(),
            });
        }
        match table_type {
            SymbolTableType::Module => {
                symbol.scope = SymbolScope::GlobalImplicit;
            }
            SymbolTableType::Class => {
                // named expressions are forbidden in comprehensions on class scope
                return Err(SymbolTableError {
                    error: "assignment expression within a comprehension cannot be used in a class body".to_string(),
                    // TODO: accurate location info, somehow
                    location: Location::default(),
                });
            }
            SymbolTableType::Function => {
                if let Some(parent_symbol) = symbols.get_mut(&symbol.name) {
                    if let SymbolScope::Unknown = parent_symbol.scope {
                        // this information is new, as the assignment is done in inner scope
                        parent_symbol.is_assigned = true;
                    }
                    symbol.scope = if parent_symbol.is_global() {
                        parent_symbol.scope
                    } else {
                        SymbolScope::Free
                    };
                } else {
                    let mut cloned_sym = symbol.clone();
                    cloned_sym.scope = SymbolScope::Local;
                    last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
                }
            }
            SymbolTableType::Comprehension => {
                // TODO check for conflicts - requires more context information about variables
                match symbols.get_mut(&symbol.name) {
                    Some(parent_symbol) => {
                        // check if assignee is an iterator in top scope
                        if parent_symbol.is_iter {
                            return Err(SymbolTableError {
                                error: format!("assignment expression cannot rebind comprehension iteration variable {}", symbol.name),
                                // TODO: accurate location info, somehow
                                location: Location::default(),
                            });
                        }
                        // we synthesize the assignment to the symbol from inner scope
                        parent_symbol.is_assigned = true; // more checks are required
                    }
                    None => {
                        // extend the scope of the inner symbol
                        // as we are in a nested comprehension, we expect that the symbol is needed
                        // outside, too, and set it therefore to non-local scope. I.e., we expect to
                        // find a definition on a higher level
                        let mut cloned_sym = symbol.clone();
                        cloned_sym.scope = SymbolScope::Free;
                        last.0.insert(cloned_sym.name.to_owned(), cloned_sym);
                    }
                }
                self.analyze_symbol_comprehension(symbol, parent_offset + 1)?;
            }
        }
        Ok(())
    }
fn analyze_symbol_comprehension ( & mut self , symbol : & mut Symbol , parent_offset : usize , ) -> SymbolTableResult { // when this is called, we expect to be in the direct parent scope of the scope that contains 'symbol' let last = self . tables . iter_mut ( ) . rev ( ) . nth ( parent_offset ) . unwrap ( ) ; let symbols = & mut last . 0 ; let table_type = last . 1 ; // it is not allowed to use an iterator variable as assignee in a named expression if symbol . is_iter { return Err ( SymbolTableError { error : format ! ( " " symbol name ) , // TODO: accurate location info, somehow location : Location :: default ( ) , } ) ; } match table_type { SymbolTableType :: Module => { symbol . scope = SymbolScope :: GlobalImplicit ; } SymbolTableType :: Class => { // named expressions are forbidden in comprehensions on class scope return Err ( SymbolTableError { error : " " . to_string ( ) , // TODO: accurate location info, somehow location : Location :: default ( ) , } ) ; } SymbolTableType :: Function => { if let Some ( parent_symbol ) = symbols . get_mut ( & symbol . name ) { if let SymbolScope :: Unknown = parent_symbol . scope { // this information is new, as the assignment is done in inner scope parent_symbol . is_assigned = true ; } symbol . scope = if parent_symbol . is_global ( ) { parent_symbol . scope } else { SymbolScope :: Free } ; } else { let mut cloned_sym = symbol . clone ( ) ; cloned_sym . scope = SymbolScope :: Local ; last . 0 . insert ( cloned_sym . name . to_owned ( ) , cloned_sym ) ; } } SymbolTableType :: Comprehension => { // TODO check for conflicts - requires more context information about variables match symbols . get_mut ( & symbol . name ) { Some ( parent_symbol ) => { // check if assignee is an iterator in top scope if parent_symbol . is_iter { return Err ( SymbolTableError { error : format ! ( " " symbol name ) , // TODO: accurate location info, somehow location : Location :: default ( ) , } ) ; } // we synthesize the assignment to the symbol from inner scope parent_symbol . is_assigned = true ; // more checks are required } None => { // extend the scope of the inner symbol // as we are in a nested comprehension, we expect that the symbol is needed // outside, too, and set it therefore to non-local scope. I.e., we expect to // find a definition on a higher level let mut cloned_sym = symbol . clone ( ) ; cloned_sym . scope = SymbolScope :: Free ; last . 0 . insert ( cloned_sym . name . to_owned ( ) , cloned_sym ) ; } } self . analyze_symbol_comprehension ( symbol , parent_offset + 1 ) ? ; } } Ok ( ( ) ) }
Implements the symbol analysis and scope extension for names
assigned by a named expression in a comprehension.
Implements the symbol analysis and scope extension for names assigned by a named expression in a comprehension .
&mut self
symbol
&mut Symbol
parent_offset
usize