diff --git a/src/main.rs b/src/main.rs index 13b145e9e6..90e4788cf2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,7 +81,7 @@ fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: String) -> Py ) .map_err(|err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) })?; // trace!("Code object: {:?}", code_obj.borrow()); let builtins = vm.get_builtin_scope(); diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index d3aaa6ee05..2ce0a6733b 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -152,7 +152,7 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { compile::compile(&source, &mode, filename, vm.ctx.code_type()).map_err(|err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) }) } @@ -206,7 +206,7 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { compile::compile(&source, &mode, "".to_string(), vm.ctx.code_type()).map_err( |err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) }, )? } else { @@ -241,7 +241,7 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { compile::compile(&source, &mode, "".to_string(), vm.ctx.code_type()).map_err( |err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) }, )? } else if objtype::isinstance(source, &vm.ctx.code_type()) { diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 067bfa4426..0563ad9bbb 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -16,6 +16,7 @@ struct Compiler { nxt_label: usize, source_path: Option, current_source_location: ast::Location, + in_loop: bool, } /// Compile a given sourcecode into a bytecode object. @@ -73,6 +74,7 @@ impl Compiler { nxt_label: 0, source_path: None, current_source_location: ast::Location::default(), + in_loop: false, } } @@ -229,7 +231,10 @@ impl Compiler { self.set_label(start_label); self.compile_test(test, None, Some(else_label), EvalContext::Statement)?; + + self.in_loop = true; self.compile_statements(body)?; + self.in_loop = false; self.emit(Instruction::Jump { target: start_label, }); @@ -290,7 +295,10 @@ impl Compiler { self.compile_store(target)?; // Body of loop: + self.in_loop = true; self.compile_statements(body)?; + self.in_loop = false; + self.emit(Instruction::Jump { target: start_label, }); @@ -563,9 +571,15 @@ impl Compiler { self.set_label(end_label); } ast::Statement::Break => { + if !self.in_loop { + return Err(CompileError::SyntaxErr(String::from("break"))); + } self.emit(Instruction::Break); } ast::Statement::Continue => { + if !self.in_loop { + return Err(CompileError::SyntaxErr(String::from("continue"))); + } self.emit(Instruction::Continue); } ast::Statement::Return { value } => { @@ -648,6 +662,7 @@ impl Compiler { name: &str, args: &ast::Parameters, ) -> Result { + self.in_loop = false; let have_kwargs = !args.defaults.is_empty(); if have_kwargs { // Construct a tuple: diff --git a/vm/src/error.rs b/vm/src/error.rs index 811a335111..0b98ab8164 100644 --- a/vm/src/error.rs +++ b/vm/src/error.rs @@ -15,6 +15,8 @@ pub enum CompileError { Parse(ParseError), // Multiple `*` detected StarArgs, + // Catches errors undetectable by the parser + SyntaxErr(String), } impl fmt::Display for CompileError { @@ -25,6 +27,7 @@ impl fmt::Display for CompileError { CompileError::ExpectExpr => write!(f, "Expecting expression, got statement"), CompileError::Parse(err) => err.fmt(f), CompileError::StarArgs => write!(f, "Two starred expressions in assignment"), + CompileError::SyntaxErr(expr) => write!(f, "Syntax Error: '{}' ouside loop", expr), } } }