From e181826b5fd675a540bdb70595ea8524d3ce54f4 Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Wed, 28 Aug 2019 16:10:30 +0200 Subject: [PATCH] Add scope type and other symboltable properties. --- compiler/src/symboltable.rs | 62 +++++++++++++++++++++++++++---------- crawl_sourcecode.py | 25 +++++++++------ vm/src/stdlib/socket.rs | 4 +-- vm/src/stdlib/symtable.rs | 30 ++++++++++++++++-- 4 files changed, 92 insertions(+), 29 deletions(-) diff --git a/compiler/src/symboltable.rs b/compiler/src/symboltable.rs index d99ae82184..3c70d4fc25 100644 --- a/compiler/src/symboltable.rs +++ b/compiler/src/symboltable.rs @@ -11,6 +11,7 @@ use crate::error::{CompileError, CompileErrorType}; use indexmap::map::IndexMap; use rustpython_parser::ast; use rustpython_parser::location::Location; +use std::fmt; pub fn make_symbol_table(program: &ast::Program) -> Result { let mut builder: SymbolTableBuilder = Default::default(); @@ -29,11 +30,17 @@ pub fn statements_to_symbol_table( } /// Captures all symbols in the current scope, and has a list of subscopes in this scope. -#[derive(Clone, Default)] +#[derive(Clone)] pub struct SymbolTable { /// The name of this symbol table. Often the name of the class or function. pub name: String, + /// The type of symbol table + pub typ: SymbolTableType, + + /// The line number in the sourcecode where this symboltable begins. + pub line_number: usize, + /// A set of symbols present on this scope level. pub symbols: IndexMap, @@ -43,15 +50,34 @@ pub struct SymbolTable { } impl SymbolTable { - fn new(name: String) -> Self { + fn new(name: String, typ: SymbolTableType, line_number: usize) -> Self { SymbolTable { name, + typ, + line_number, symbols: Default::default(), sub_tables: vec![], } } } +#[derive(Clone)] +pub enum SymbolTableType { + Module, + Class, + Function, +} + +impl fmt::Display for SymbolTableType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SymbolTableType::Module => write!(f, "module"), + SymbolTableType::Class => write!(f, "class"), + SymbolTableType::Function => write!(f, "function"), + } + } +} + /// Indicator for a single symbol what the scope of this symbol is. /// The scope can be unknown, which is unfortunate, but not impossible. #[derive(Debug, Clone)] @@ -263,7 +289,7 @@ enum ExpressionContext { impl SymbolTableBuilder { fn prepare(&mut self) { - self.enter_block("top") + self.enter_scope("top", SymbolTableType::Module, 0) } fn finish(&mut self) -> Result { @@ -273,14 +299,13 @@ impl SymbolTableBuilder { Ok(symbol_table) } - fn enter_block(&mut self, name: &str) { - // let parent = Some(self.tables.last().unwrap().clone()); - let table = SymbolTable::new(name.to_string()); + fn enter_scope(&mut self, name: &str, typ: SymbolTableType, line_number: usize) { + let table = SymbolTable::new(name.to_string(), typ, line_number); self.tables.push(table); } - fn leave_block(&mut self) { - // Pop symbol table and add to sub table of parent table. + /// Pop symbol table and add to sub table of parent table. + fn leave_scope(&mut self) { let table = self.tables.pop().unwrap(); self.tables.last_mut().unwrap().sub_tables.push(table); } @@ -348,9 +373,9 @@ impl SymbolTableBuilder { if let Some(expression) = returns { self.scan_expression(expression, &ExpressionContext::Load)?; } - self.enter_function(name, args)?; + self.enter_function(name, args, statement.location.row())?; self.scan_statements(body)?; - self.leave_block(); + self.leave_scope(); } ClassDef { name, @@ -360,9 +385,9 @@ impl SymbolTableBuilder { decorator_list, } => { self.register_name(name, SymbolUsage::Assigned)?; - self.enter_block(name); + self.enter_scope(name, SymbolTableType::Class, statement.location.row()); self.scan_statements(body)?; - self.leave_block(); + self.leave_scope(); self.scan_expressions(bases, &ExpressionContext::Load)?; for keyword in keywords { self.scan_expression(&keyword.value, &ExpressionContext::Load)?; @@ -612,9 +637,9 @@ impl SymbolTableBuilder { } } Lambda { args, body } => { - self.enter_function("lambda", args)?; + self.enter_function("lambda", args, expression.location.row())?; self.scan_expression(body, &ExpressionContext::Load)?; - self.leave_block(); + self.leave_scope(); } IfExpression { test, body, orelse } => { self.scan_expression(test, &ExpressionContext::Load)?; @@ -625,7 +650,12 @@ impl SymbolTableBuilder { Ok(()) } - fn enter_function(&mut self, name: &str, args: &ast::Parameters) -> SymbolTableResult { + fn enter_function( + &mut self, + name: &str, + args: &ast::Parameters, + line_number: usize, + ) -> SymbolTableResult { // Evaluate eventual default parameters: self.scan_expressions(&args.defaults, &ExpressionContext::Load)?; for kw_default in &args.kw_defaults { @@ -644,7 +674,7 @@ impl SymbolTableBuilder { self.scan_parameter_annotation(name)?; } - self.enter_block(name); + self.enter_scope(name, SymbolTableType::Function, line_number); // Fill scope with parameter names: self.scan_parameters(&args.args)?; diff --git a/crawl_sourcecode.py b/crawl_sourcecode.py index 7e1290220d..2daad4f682 100644 --- a/crawl_sourcecode.py +++ b/crawl_sourcecode.py @@ -26,11 +26,12 @@ print(t) shift = 3 def print_node(node, indent=0): + indents = ' ' * indent if isinstance(node, ast.AST): lineno = 'row={}'.format(node.lineno) if hasattr(node, 'lineno') else '' - print(' '*indent, "NODE", node.__class__.__name__, lineno) + print(indents, "NODE", node.__class__.__name__, lineno) for field in node._fields: - print(' '*indent,'-', field) + print(indents,'-', field) f = getattr(node, field) if isinstance(f, list): for f2 in f: @@ -38,7 +39,7 @@ def print_node(node, indent=0): else: print_node(f, indent=indent+shift) else: - print(' '*indent, 'OBJ', node) + print(indents, 'OBJ', node) print_node(t) @@ -53,18 +54,24 @@ flag_names = [ ] def print_table(table, indent=0): - print(' '*indent, 'table:', table.get_name()) - print(' '*indent, ' ', 'Syms:') + indents = ' ' * indent + print(indents, 'table:', table.get_name()) + print(indents, ' ', 'name:', table.get_name()) + print(indents, ' ', 'type:', table.get_type()) + print(indents, ' ', 'line:', table.get_lineno()) + print(indents, ' ', 'identifiers:', table.get_identifiers()) + print(indents, ' ', 'Syms:') for sym in table.get_symbols(): flags = [] for flag_name in flag_names: func = getattr(sym, flag_name) if func(): flags.append(flag_name) - print(' '*indent, ' sym:', sym.get_name(), 'flags:', ' '.join(flags)) - print(' '*indent, ' ', 'Child tables:') - for child in table.get_children(): - print_table(child, indent=indent+shift) + print(indents, ' sym:', sym.get_name(), 'flags:', ' '.join(flags)) + if table.has_children(): + print(indents, ' ', 'Child tables:') + for child in table.get_children(): + print_table(child, indent=indent+shift) table = symtable.symtable(source, 'a', 'exec') print_table(table) diff --git a/vm/src/stdlib/socket.rs b/vm/src/stdlib/socket.rs index e0fd0a505e..0a9814f9ed 100644 --- a/vm/src/stdlib/socket.rs +++ b/vm/src/stdlib/socket.rs @@ -430,10 +430,10 @@ impl SocketRef { self.timeout.borrow_mut().replace(Duration::from_secs(0)); } if let Some(conn) = self.con.borrow_mut().as_mut() { - return match conn.setblocking(value) { + match conn.setblocking(value) { Ok(_) => Ok(()), Err(err) => Err(vm.new_os_error(err.to_string())), - }; + } } else { Ok(()) } diff --git a/vm/src/stdlib/symtable.rs b/vm/src/stdlib/symtable.rs index a6cf985046..0c40428919 100644 --- a/vm/src/stdlib/symtable.rs +++ b/vm/src/stdlib/symtable.rs @@ -83,8 +83,18 @@ impl PyValue for PySymbolTable { #[pyimpl] impl PySymbolTable { #[pymethod(name = "get_name")] - fn get_name(&self, vm: &VirtualMachine) -> PyResult { - Ok(vm.ctx.new_str(self.symtable.name.clone())) + fn get_name(&self, _vm: &VirtualMachine) -> String { + self.symtable.name.clone() + } + + #[pymethod(name = "get_type")] + fn get_type(&self, _vm: &VirtualMachine) -> String { + self.symtable.typ.to_string() + } + + #[pymethod(name = "get_lineno")] + fn get_lineno(&self, _vm: &VirtualMachine) -> usize { + self.symtable.line_number } #[pymethod(name = "lookup")] @@ -100,6 +110,17 @@ impl PySymbolTable { } } + #[pymethod(name = "get_identifiers")] + fn get_identifiers(&self, vm: &VirtualMachine) -> PyResult { + let symbols = self + .symtable + .symbols + .keys() + .map(|s| vm.ctx.new_str(s.to_string())) + .collect(); + Ok(vm.ctx.new_list(symbols)) + } + #[pymethod(name = "get_symbols")] fn get_symbols(&self, vm: &VirtualMachine) -> PyResult { let symbols = self @@ -111,6 +132,11 @@ impl PySymbolTable { Ok(vm.ctx.new_list(symbols)) } + #[pymethod(name = "has_children")] + fn has_children(&self, _vm: &VirtualMachine) -> bool { + !self.symtable.sub_tables.is_empty() + } + #[pymethod(name = "get_children")] fn get_children(&self, vm: &VirtualMachine) -> PyResult { let children = self