Skip to content

Commit 036f464

Browse files
Merge pull request RustPython#1325 from RustPython/scoping
Add scope type and other symboltable properties.
2 parents 39f54aa + e181826 commit 036f464

File tree

4 files changed

+92
-29
lines changed

4 files changed

+92
-29
lines changed

compiler/src/symboltable.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::error::{CompileError, CompileErrorType};
1111
use indexmap::map::IndexMap;
1212
use rustpython_parser::ast;
1313
use rustpython_parser::location::Location;
14+
use std::fmt;
1415

1516
pub fn make_symbol_table(program: &ast::Program) -> Result<SymbolTable, SymbolTableError> {
1617
let mut builder: SymbolTableBuilder = Default::default();
@@ -29,11 +30,17 @@ pub fn statements_to_symbol_table(
2930
}
3031

3132
/// Captures all symbols in the current scope, and has a list of subscopes in this scope.
32-
#[derive(Clone, Default)]
33+
#[derive(Clone)]
3334
pub struct SymbolTable {
3435
/// The name of this symbol table. Often the name of the class or function.
3536
pub name: String,
3637

38+
/// The type of symbol table
39+
pub typ: SymbolTableType,
40+
41+
/// The line number in the sourcecode where this symboltable begins.
42+
pub line_number: usize,
43+
3744
/// A set of symbols present on this scope level.
3845
pub symbols: IndexMap<String, Symbol>,
3946

@@ -43,15 +50,34 @@ pub struct SymbolTable {
4350
}
4451

4552
impl SymbolTable {
46-
fn new(name: String) -> Self {
53+
fn new(name: String, typ: SymbolTableType, line_number: usize) -> Self {
4754
SymbolTable {
4855
name,
56+
typ,
57+
line_number,
4958
symbols: Default::default(),
5059
sub_tables: vec![],
5160
}
5261
}
5362
}
5463

64+
#[derive(Clone)]
65+
pub enum SymbolTableType {
66+
Module,
67+
Class,
68+
Function,
69+
}
70+
71+
impl fmt::Display for SymbolTableType {
72+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73+
match self {
74+
SymbolTableType::Module => write!(f, "module"),
75+
SymbolTableType::Class => write!(f, "class"),
76+
SymbolTableType::Function => write!(f, "function"),
77+
}
78+
}
79+
}
80+
5581
/// Indicator for a single symbol what the scope of this symbol is.
5682
/// The scope can be unknown, which is unfortunate, but not impossible.
5783
#[derive(Debug, Clone)]
@@ -263,7 +289,7 @@ enum ExpressionContext {
263289

264290
impl SymbolTableBuilder {
265291
fn prepare(&mut self) {
266-
self.enter_block("top")
292+
self.enter_scope("top", SymbolTableType::Module, 0)
267293
}
268294

269295
fn finish(&mut self) -> Result<SymbolTable, SymbolTableError> {
@@ -273,14 +299,13 @@ impl SymbolTableBuilder {
273299
Ok(symbol_table)
274300
}
275301

276-
fn enter_block(&mut self, name: &str) {
277-
// let parent = Some(self.tables.last().unwrap().clone());
278-
let table = SymbolTable::new(name.to_string());
302+
fn enter_scope(&mut self, name: &str, typ: SymbolTableType, line_number: usize) {
303+
let table = SymbolTable::new(name.to_string(), typ, line_number);
279304
self.tables.push(table);
280305
}
281306

282-
fn leave_block(&mut self) {
283-
// Pop symbol table and add to sub table of parent table.
307+
/// Pop symbol table and add to sub table of parent table.
308+
fn leave_scope(&mut self) {
284309
let table = self.tables.pop().unwrap();
285310
self.tables.last_mut().unwrap().sub_tables.push(table);
286311
}
@@ -348,9 +373,9 @@ impl SymbolTableBuilder {
348373
if let Some(expression) = returns {
349374
self.scan_expression(expression, &ExpressionContext::Load)?;
350375
}
351-
self.enter_function(name, args)?;
376+
self.enter_function(name, args, statement.location.row())?;
352377
self.scan_statements(body)?;
353-
self.leave_block();
378+
self.leave_scope();
354379
}
355380
ClassDef {
356381
name,
@@ -360,9 +385,9 @@ impl SymbolTableBuilder {
360385
decorator_list,
361386
} => {
362387
self.register_name(name, SymbolUsage::Assigned)?;
363-
self.enter_block(name);
388+
self.enter_scope(name, SymbolTableType::Class, statement.location.row());
364389
self.scan_statements(body)?;
365-
self.leave_block();
390+
self.leave_scope();
366391
self.scan_expressions(bases, &ExpressionContext::Load)?;
367392
for keyword in keywords {
368393
self.scan_expression(&keyword.value, &ExpressionContext::Load)?;
@@ -612,9 +637,9 @@ impl SymbolTableBuilder {
612637
}
613638
}
614639
Lambda { args, body } => {
615-
self.enter_function("lambda", args)?;
640+
self.enter_function("lambda", args, expression.location.row())?;
616641
self.scan_expression(body, &ExpressionContext::Load)?;
617-
self.leave_block();
642+
self.leave_scope();
618643
}
619644
IfExpression { test, body, orelse } => {
620645
self.scan_expression(test, &ExpressionContext::Load)?;
@@ -625,7 +650,12 @@ impl SymbolTableBuilder {
625650
Ok(())
626651
}
627652

628-
fn enter_function(&mut self, name: &str, args: &ast::Parameters) -> SymbolTableResult {
653+
fn enter_function(
654+
&mut self,
655+
name: &str,
656+
args: &ast::Parameters,
657+
line_number: usize,
658+
) -> SymbolTableResult {
629659
// Evaluate eventual default parameters:
630660
self.scan_expressions(&args.defaults, &ExpressionContext::Load)?;
631661
for kw_default in &args.kw_defaults {
@@ -644,7 +674,7 @@ impl SymbolTableBuilder {
644674
self.scan_parameter_annotation(name)?;
645675
}
646676

647-
self.enter_block(name);
677+
self.enter_scope(name, SymbolTableType::Function, line_number);
648678

649679
// Fill scope with parameter names:
650680
self.scan_parameters(&args.args)?;

crawl_sourcecode.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,20 @@
2626

2727
shift = 3
2828
def print_node(node, indent=0):
29+
indents = ' ' * indent
2930
if isinstance(node, ast.AST):
3031
lineno = 'row={}'.format(node.lineno) if hasattr(node, 'lineno') else ''
31-
print(' '*indent, "NODE", node.__class__.__name__, lineno)
32+
print(indents, "NODE", node.__class__.__name__, lineno)
3233
for field in node._fields:
33-
print(' '*indent,'-', field)
34+
print(indents,'-', field)
3435
f = getattr(node, field)
3536
if isinstance(f, list):
3637
for f2 in f:
3738
print_node(f2, indent=indent+shift)
3839
else:
3940
print_node(f, indent=indent+shift)
4041
else:
41-
print(' '*indent, 'OBJ', node)
42+
print(indents, 'OBJ', node)
4243

4344
print_node(t)
4445

@@ -53,18 +54,24 @@ def print_node(node, indent=0):
5354
]
5455

5556
def print_table(table, indent=0):
56-
print(' '*indent, 'table:', table.get_name())
57-
print(' '*indent, ' ', 'Syms:')
57+
indents = ' ' * indent
58+
print(indents, 'table:', table.get_name())
59+
print(indents, ' ', 'name:', table.get_name())
60+
print(indents, ' ', 'type:', table.get_type())
61+
print(indents, ' ', 'line:', table.get_lineno())
62+
print(indents, ' ', 'identifiers:', table.get_identifiers())
63+
print(indents, ' ', 'Syms:')
5864
for sym in table.get_symbols():
5965
flags = []
6066
for flag_name in flag_names:
6167
func = getattr(sym, flag_name)
6268
if func():
6369
flags.append(flag_name)
64-
print(' '*indent, ' sym:', sym.get_name(), 'flags:', ' '.join(flags))
65-
print(' '*indent, ' ', 'Child tables:')
66-
for child in table.get_children():
67-
print_table(child, indent=indent+shift)
70+
print(indents, ' sym:', sym.get_name(), 'flags:', ' '.join(flags))
71+
if table.has_children():
72+
print(indents, ' ', 'Child tables:')
73+
for child in table.get_children():
74+
print_table(child, indent=indent+shift)
6875

6976
table = symtable.symtable(source, 'a', 'exec')
7077
print_table(table)

vm/src/stdlib/socket.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,10 +430,10 @@ impl SocketRef {
430430
self.timeout.borrow_mut().replace(Duration::from_secs(0));
431431
}
432432
if let Some(conn) = self.con.borrow_mut().as_mut() {
433-
return match conn.setblocking(value) {
433+
match conn.setblocking(value) {
434434
Ok(_) => Ok(()),
435435
Err(err) => Err(vm.new_os_error(err.to_string())),
436-
};
436+
}
437437
} else {
438438
Ok(())
439439
}

vm/src/stdlib/symtable.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,18 @@ impl PyValue for PySymbolTable {
8383
#[pyimpl]
8484
impl PySymbolTable {
8585
#[pymethod(name = "get_name")]
86-
fn get_name(&self, vm: &VirtualMachine) -> PyResult {
87-
Ok(vm.ctx.new_str(self.symtable.name.clone()))
86+
fn get_name(&self, _vm: &VirtualMachine) -> String {
87+
self.symtable.name.clone()
88+
}
89+
90+
#[pymethod(name = "get_type")]
91+
fn get_type(&self, _vm: &VirtualMachine) -> String {
92+
self.symtable.typ.to_string()
93+
}
94+
95+
#[pymethod(name = "get_lineno")]
96+
fn get_lineno(&self, _vm: &VirtualMachine) -> usize {
97+
self.symtable.line_number
8898
}
8999

90100
#[pymethod(name = "lookup")]
@@ -100,6 +110,17 @@ impl PySymbolTable {
100110
}
101111
}
102112

113+
#[pymethod(name = "get_identifiers")]
114+
fn get_identifiers(&self, vm: &VirtualMachine) -> PyResult {
115+
let symbols = self
116+
.symtable
117+
.symbols
118+
.keys()
119+
.map(|s| vm.ctx.new_str(s.to_string()))
120+
.collect();
121+
Ok(vm.ctx.new_list(symbols))
122+
}
123+
103124
#[pymethod(name = "get_symbols")]
104125
fn get_symbols(&self, vm: &VirtualMachine) -> PyResult {
105126
let symbols = self
@@ -111,6 +132,11 @@ impl PySymbolTable {
111132
Ok(vm.ctx.new_list(symbols))
112133
}
113134

135+
#[pymethod(name = "has_children")]
136+
fn has_children(&self, _vm: &VirtualMachine) -> bool {
137+
!self.symtable.sub_tables.is_empty()
138+
}
139+
114140
#[pymethod(name = "get_children")]
115141
fn get_children(&self, vm: &VirtualMachine) -> PyResult {
116142
let children = self

0 commit comments

Comments
 (0)