diff --git a/compiler/src/symboltable.rs b/compiler/src/symboltable.rs index d91f32dc7..56d106704 100644 --- a/compiler/src/symboltable.rs +++ b/compiler/src/symboltable.rs @@ -204,8 +204,25 @@ impl SymbolTableAnalyzer { // all is well } SymbolScope::Unknown => { - if symbol.is_assigned { + // Try hard to figure out what the scope of this symbol is. + + if symbol.is_assigned || symbol.is_parameter { symbol.scope = SymbolScope::Local; + } else { + // TODO: comment this out and make it work properly: + /* + let found_in_outer_scope = self + .tables + .iter() + .any(|t| t.symbols.contains_key(&symbol.name)); + if found_in_outer_scope { + // Symbol is in some outer scope. + + } else { + // Well, it must be a global then :) + // symbol.scope = SymbolScope::Global; + } + */ } } } @@ -710,7 +727,10 @@ impl SymbolTableBuilder { }); } } - SymbolUsage::Parameter | SymbolUsage::Assigned => { + SymbolUsage::Parameter => { + symbol.is_parameter = true; + } + SymbolUsage::Assigned => { symbol.is_assigned = true; } SymbolUsage::Global => { diff --git a/vm/src/scope.rs b/vm/src/scope.rs index 9e5baadb7..c451e8106 100644 --- a/vm/src/scope.rs +++ b/vm/src/scope.rs @@ -138,11 +138,8 @@ impl NameProtocol for Scope { } } - if let Some(value) = self.globals.get_item_option(name, vm).unwrap() { - return Some(value); - } - - vm.get_attribute(vm.builtins.clone(), name).ok() + // Fall back to loading a global after all scopes have been searched! + self.load_global(vm, name) } #[cfg_attr(feature = "flame-it", flame("Scope"))] @@ -174,7 +171,11 @@ impl NameProtocol for Scope { #[cfg_attr(feature = "flame-it", flame("Scope"))] fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option { - self.globals.get_item_option(name, vm).unwrap() + if let Some(value) = self.globals.get_item_option(name, vm).unwrap() { + Some(value) + } else { + vm.get_attribute(vm.builtins.clone(), name).ok() + } } fn store_global(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef) { diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 19a4e084a..85c8fd8a4 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -252,7 +252,7 @@ fn optional_statements_to_ast( let statements = if let Some(statements) = statements { statements_to_ast(vm, statements)?.into_object() } else { - vm.ctx.none() + vm.ctx.new_list(vec![]) }; Ok(statements) } @@ -283,6 +283,17 @@ fn make_string_list(vm: &VirtualMachine, names: &[String]) -> PyObjectRef { ) } +fn optional_expressions_to_ast( + vm: &VirtualMachine, + expressions: &[Option], +) -> PyResult { + let py_expression_nodes: PyResult<_> = expressions + .iter() + .map(|expression| Ok(optional_expression_to_ast(vm, expression)?)) + .collect(); + Ok(vm.ctx.new_list(py_expression_nodes?).downcast().unwrap()) +} + fn optional_expression_to_ast(vm: &VirtualMachine, value: &Option) -> PyResult { let value = if let Some(value) = value { expression_to_ast(vm, value)?.into_object() @@ -526,8 +537,23 @@ fn operator_string(op: &ast::Operator) -> String { } fn parameters_to_ast(vm: &VirtualMachine, args: &ast::Parameters) -> PyResult { - let args = map_ast(parameter_to_ast, vm, &args.args)?; - Ok(node!(vm, arguments, { args => args })) + Ok(node!(vm, arguments, { + args => map_ast(parameter_to_ast, vm, &args.args)?, + vararg => vararg_to_ast(vm, &args.vararg)?, + kwonlyargs => map_ast(parameter_to_ast, vm, &args.kwonlyargs)?, + kw_defaults => optional_expressions_to_ast(vm, &args.kw_defaults)?, + kwarg => vararg_to_ast(vm, &args.kwarg)?, + defaults => expressions_to_ast(vm, &args.defaults)? + })) +} + +fn vararg_to_ast(vm: &VirtualMachine, vararg: &ast::Varargs) -> PyResult { + let py_node = match vararg { + ast::Varargs::None => vm.get_none(), + ast::Varargs::Unnamed => vm.get_none(), + ast::Varargs::Named(parameter) => parameter_to_ast(vm, parameter)?.into_object(), + }; + Ok(py_node) } fn parameter_to_ast(vm: &VirtualMachine, parameter: &ast::Parameter) -> PyResult { @@ -537,10 +563,15 @@ fn parameter_to_ast(vm: &VirtualMachine, parameter: &ast::Parameter) -> PyResult vm.ctx.none() }; - Ok(node!(vm, arg, { + let py_node = node!(vm, arg, { arg => vm.ctx.new_str(parameter.arg.to_string()), annotation => py_annotation - })) + }); + + let lineno = vm.ctx.new_int(parameter.location.row()); + vm.set_attr(py_node.as_object(), "lineno", lineno)?; + + Ok(py_node) } fn optional_string_to_py_obj(vm: &VirtualMachine, name: &Option) -> PyObjectRef {