Skip to content

Commit 71b6e2a

Browse files
Merge pull request RustPython#806 from RustPython/symbol-table
Initial version of symbol table builder.
2 parents 8f3319e + 733d3a1 commit 71b6e2a

File tree

6 files changed

+633
-48
lines changed

6 files changed

+633
-48
lines changed

tests/snippets/global_nonlocal.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
# Test global and nonlocal funkyness
3+
4+
a = 2
5+
6+
def b():
7+
global a
8+
a = 4
9+
10+
assert a == 2
11+
b()
12+
assert a == 4
13+

vm/src/bytecode.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ bitflags! {
3838

3939
pub type Label = usize;
4040

41+
#[derive(Debug, Clone, PartialEq)]
42+
pub enum NameScope {
43+
Local,
44+
Global,
45+
}
46+
4147
/// A Single bytecode instruction.
4248
#[derive(Debug, Clone, PartialEq)]
4349
pub enum Instruction {
@@ -50,9 +56,11 @@ pub enum Instruction {
5056
},
5157
LoadName {
5258
name: String,
59+
scope: NameScope,
5360
},
5461
StoreName {
5562
name: String,
63+
scope: NameScope,
5664
},
5765
DeleteName {
5866
name: String,
@@ -322,8 +330,8 @@ impl Instruction {
322330
match self {
323331
Import { name, symbol } => w!(Import, name, format!("{:?}", symbol)),
324332
ImportStar { name } => w!(ImportStar, name),
325-
LoadName { name } => w!(LoadName, name),
326-
StoreName { name } => w!(StoreName, name),
333+
LoadName { name, scope } => w!(LoadName, name, format!("{:?}", scope)),
334+
StoreName { name, scope } => w!(StoreName, name, format!("{:?}", scope)),
327335
DeleteName { name } => w!(DeleteName, name),
328336
StoreSubscript => w!(StoreSubscript),
329337
DeleteSubscript => w!(DeleteSubscript),

vm/src/compile.rs

Lines changed: 96 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ use crate::error::CompileError;
1010
use crate::obj::objcode;
1111
use crate::obj::objcode::PyCodeRef;
1212
use crate::pyobject::PyValue;
13+
use crate::symboltable::{make_symbol_table, statements_to_symbol_table, SymbolRole, SymbolScope};
1314
use crate::VirtualMachine;
1415
use num_complex::Complex64;
1516
use rustpython_parser::{ast, parser};
1617

1718
struct Compiler {
1819
code_object_stack: Vec<CodeObject>,
20+
scope_stack: Vec<SymbolScope>,
1921
nxt_label: usize,
2022
source_path: Option<String>,
2123
current_source_location: ast::Location,
@@ -38,15 +40,18 @@ pub fn compile(
3840
match mode {
3941
Mode::Exec => {
4042
let ast = parser::parse_program(source).map_err(CompileError::Parse)?;
41-
compiler.compile_program(&ast)
43+
let symbol_table = make_symbol_table(&ast);
44+
compiler.compile_program(&ast, symbol_table)
4245
}
4346
Mode::Eval => {
4447
let statement = parser::parse_statement(source).map_err(CompileError::Parse)?;
45-
compiler.compile_statement_eval(&statement)
48+
let symbol_table = statements_to_symbol_table(&statement);
49+
compiler.compile_statement_eval(&statement, symbol_table)
4650
}
4751
Mode::Single => {
4852
let ast = parser::parse_program(source).map_err(CompileError::Parse)?;
49-
compiler.compile_program_single(&ast)
53+
let symbol_table = make_symbol_table(&ast);
54+
compiler.compile_program_single(&ast, symbol_table)
5055
}
5156
}?;
5257

@@ -73,6 +78,7 @@ impl Compiler {
7378
fn new() -> Self {
7479
Compiler {
7580
code_object_stack: Vec::new(),
81+
scope_stack: Vec::new(),
7682
nxt_label: 0,
7783
source_path: None,
7884
current_source_location: ast::Location::default(),
@@ -96,11 +102,17 @@ impl Compiler {
96102
}
97103

98104
fn pop_code_object(&mut self) -> CodeObject {
105+
// self.scope_stack.pop().unwrap();
99106
self.code_object_stack.pop().unwrap()
100107
}
101108

102-
fn compile_program(&mut self, program: &ast::Program) -> Result<(), CompileError> {
109+
fn compile_program(
110+
&mut self,
111+
program: &ast::Program,
112+
symbol_scope: SymbolScope,
113+
) -> Result<(), CompileError> {
103114
let size_before = self.code_object_stack.len();
115+
self.scope_stack.push(symbol_scope);
104116
self.compile_statements(&program.statements)?;
105117
assert!(self.code_object_stack.len() == size_before);
106118

@@ -112,7 +124,12 @@ impl Compiler {
112124
Ok(())
113125
}
114126

115-
fn compile_program_single(&mut self, program: &ast::Program) -> Result<(), CompileError> {
127+
fn compile_program_single(
128+
&mut self,
129+
program: &ast::Program,
130+
symbol_scope: SymbolScope,
131+
) -> Result<(), CompileError> {
132+
self.scope_stack.push(symbol_scope);
116133
for statement in &program.statements {
117134
if let ast::Statement::Expression { ref expression } = statement.node {
118135
self.compile_expression(expression)?;
@@ -132,7 +149,9 @@ impl Compiler {
132149
fn compile_statement_eval(
133150
&mut self,
134151
statements: &[ast::LocatedStatement],
152+
symbol_table: SymbolScope,
135153
) -> Result<(), CompileError> {
154+
self.scope_stack.push(symbol_table);
136155
for statement in statements {
137156
if let ast::Statement::Expression { ref expression } = statement.node {
138157
self.compile_expression(expression)?;
@@ -154,6 +173,31 @@ impl Compiler {
154173
Ok(())
155174
}
156175

176+
fn scope_for_name(&self, name: &str) -> bytecode::NameScope {
177+
let role = self.lookup_name(name);
178+
match role {
179+
SymbolRole::Global => bytecode::NameScope::Global,
180+
_ => bytecode::NameScope::Local,
181+
}
182+
}
183+
184+
fn load_name(&mut self, name: &str) {
185+
// TODO: if global, do something else!
186+
let scope = self.scope_for_name(name);
187+
self.emit(Instruction::LoadName {
188+
name: name.to_string(),
189+
scope,
190+
});
191+
}
192+
193+
fn store_name(&mut self, name: &str) {
194+
let scope = self.scope_for_name(name);
195+
self.emit(Instruction::StoreName {
196+
name: name.to_string(),
197+
scope,
198+
});
199+
}
200+
157201
fn compile_statement(&mut self, statement: &ast::LocatedStatement) -> Result<(), CompileError> {
158202
trace!("Compiling {:?}", statement);
159203
self.set_source_location(&statement.location);
@@ -177,15 +221,14 @@ impl Compiler {
177221
name: module.clone(),
178222
symbol: symbol.clone(),
179223
});
180-
self.emit(Instruction::StoreName {
181-
name: match alias {
182-
Some(alias) => alias.clone(),
183-
None => match symbol {
184-
Some(symbol) => symbol.clone(),
185-
None => module.clone(),
186-
},
224+
let name = match alias {
225+
Some(alias) => alias.clone(),
226+
None => match symbol {
227+
Some(symbol) => symbol.clone(),
228+
None => module.clone(),
187229
},
188-
});
230+
};
231+
self.store_name(&name);
189232
}
190233
}
191234
}
@@ -196,11 +239,8 @@ impl Compiler {
196239
// Pop result of stack, since we not use it:
197240
self.emit(Instruction::Pop);
198241
}
199-
ast::Statement::Global { names } => {
200-
unimplemented!("global {:?}", names);
201-
}
202-
ast::Statement::Nonlocal { names } => {
203-
unimplemented!("nonlocal {:?}", names);
242+
ast::Statement::Global { .. } | ast::Statement::Nonlocal { .. } => {
243+
// Handled during symbol table construction.
204244
}
205245
ast::Statement::If { test, body, orelse } => {
206246
let end_label = self.new_label();
@@ -323,6 +363,7 @@ impl Compiler {
323363
self.compile_test(test, Some(end_label), None, EvalContext::Statement)?;
324364
self.emit(Instruction::LoadName {
325365
name: String::from("AssertionError"),
366+
scope: bytecode::NameScope::Local,
326367
});
327368
match msg {
328369
Some(e) => {
@@ -466,6 +507,7 @@ impl Compiler {
466507
line_number,
467508
name.to_string(),
468509
));
510+
self.enter_scope();
469511

470512
let mut flags = bytecode::FunctionOpArg::empty();
471513
if have_defaults {
@@ -529,6 +571,7 @@ impl Compiler {
529571
// Check exception type:
530572
self.emit(Instruction::LoadName {
531573
name: String::from("isinstance"),
574+
scope: bytecode::NameScope::Local,
532575
});
533576
self.emit(Instruction::Rotate { amount: 2 });
534577
self.compile_expression(exc_type)?;
@@ -543,9 +586,7 @@ impl Compiler {
543586

544587
// We have a match, store in name (except x as y)
545588
if let Some(alias) = &handler.name {
546-
self.emit(Instruction::StoreName {
547-
name: alias.clone(),
548-
});
589+
self.store_name(alias);
549590
} else {
550591
// Drop exception from top of stack:
551592
self.emit(Instruction::Pop);
@@ -630,6 +671,7 @@ impl Compiler {
630671
});
631672
self.emit(Instruction::ReturnValue);
632673
let code = self.pop_code_object();
674+
self.leave_scope();
633675

634676
// Prepare type annotations:
635677
let mut num_annotations = 0;
@@ -683,9 +725,7 @@ impl Compiler {
683725
self.store_docstring(doc_str);
684726
self.apply_decorators(decorator_list);
685727

686-
self.emit(Instruction::StoreName {
687-
name: name.to_string(),
688-
});
728+
self.store_name(name);
689729

690730
self.current_qualified_path = old_qualified_path;
691731
self.in_loop = was_in_loop;
@@ -720,14 +760,17 @@ impl Compiler {
720760
line_number,
721761
name.to_string(),
722762
));
763+
self.enter_scope();
723764

724765
let (new_body, doc_str) = get_doc(body);
725766

726767
self.emit(Instruction::LoadName {
727768
name: "__name__".to_string(),
769+
scope: bytecode::NameScope::Local,
728770
});
729771
self.emit(Instruction::StoreName {
730772
name: "__module__".to_string(),
773+
scope: bytecode::NameScope::Local,
731774
});
732775
self.compile_statements(new_body)?;
733776
self.emit(Instruction::LoadConst {
@@ -736,6 +779,7 @@ impl Compiler {
736779
self.emit(Instruction::ReturnValue);
737780

738781
let code = self.pop_code_object();
782+
self.leave_scope();
739783

740784
self.emit(Instruction::LoadConst {
741785
value: bytecode::Constant::Code {
@@ -794,9 +838,7 @@ impl Compiler {
794838
self.store_docstring(doc_str);
795839
self.apply_decorators(decorator_list);
796840

797-
self.emit(Instruction::StoreName {
798-
name: name.to_string(),
799-
});
841+
self.store_name(name);
800842
self.current_qualified_path = old_qualified_path;
801843
self.in_loop = was_in_loop;
802844
Ok(())
@@ -942,9 +984,7 @@ impl Compiler {
942984
fn compile_store(&mut self, target: &ast::Expression) -> Result<(), CompileError> {
943985
match target {
944986
ast::Expression::Identifier { name } => {
945-
self.emit(Instruction::StoreName {
946-
name: name.to_string(),
947-
});
987+
self.store_name(name);
948988
}
949989
ast::Expression::Subscript { a, b } => {
950990
self.compile_expression(a)?;
@@ -1231,9 +1271,7 @@ impl Compiler {
12311271
});
12321272
}
12331273
ast::Expression::Identifier { name } => {
1234-
self.emit(Instruction::LoadName {
1235-
name: name.to_string(),
1236-
});
1274+
self.load_name(name);
12371275
}
12381276
ast::Expression::Lambda { args, body } => {
12391277
let name = "<lambda>".to_string();
@@ -1242,6 +1280,7 @@ impl Compiler {
12421280
self.compile_expression(body)?;
12431281
self.emit(Instruction::ReturnValue);
12441282
let code = self.pop_code_object();
1283+
self.leave_scope();
12451284
self.emit(Instruction::LoadConst {
12461285
value: bytecode::Constant::Code {
12471286
code: Box::new(code),
@@ -1449,6 +1488,7 @@ impl Compiler {
14491488
// Load iterator onto stack (passed as first argument):
14501489
self.emit(Instruction::LoadName {
14511490
name: String::from(".0"),
1491+
scope: bytecode::NameScope::Local,
14521492
});
14531493
} else {
14541494
// Evaluate iterated item:
@@ -1588,6 +1628,26 @@ impl Compiler {
15881628
Ok(())
15891629
}
15901630

1631+
// Scope helpers:
1632+
fn enter_scope(&mut self) {
1633+
// println!("Enter scope {:?}", self.scope_stack);
1634+
// Enter first subscope!
1635+
let scope = self.scope_stack.last_mut().unwrap().sub_scopes.remove(0);
1636+
self.scope_stack.push(scope);
1637+
}
1638+
1639+
fn leave_scope(&mut self) {
1640+
// println!("Leave scope {:?}", self.scope_stack);
1641+
let scope = self.scope_stack.pop().unwrap();
1642+
assert!(scope.sub_scopes.is_empty());
1643+
}
1644+
1645+
fn lookup_name(&self, name: &str) -> &SymbolRole {
1646+
// println!("Looking up {:?}", name);
1647+
let scope = self.scope_stack.last().unwrap();
1648+
scope.lookup(name).unwrap()
1649+
}
1650+
15911651
// Low level helper functions:
15921652
fn emit(&mut self, instruction: Instruction) {
15931653
let location = self.current_source_location.clone();
@@ -1657,14 +1717,16 @@ mod tests {
16571717
use crate::bytecode::CodeObject;
16581718
use crate::bytecode::Constant::*;
16591719
use crate::bytecode::Instruction::*;
1720+
use crate::symboltable::make_symbol_table;
16601721
use rustpython_parser::parser;
16611722

16621723
fn compile_exec(source: &str) -> CodeObject {
16631724
let mut compiler = Compiler::new();
16641725
compiler.source_path = Some("source_path".to_string());
16651726
compiler.push_new_code_object("<module>".to_string());
16661727
let ast = parser::parse_program(&source.to_string()).unwrap();
1667-
compiler.compile_program(&ast).unwrap();
1728+
let symbol_scope = make_symbol_table(&ast);
1729+
compiler.compile_program(&ast, symbol_scope).unwrap();
16681730
compiler.pop_code_object()
16691731
}
16701732

0 commit comments

Comments
 (0)