diff --git a/compiler/src/compile.rs b/compiler/src/compile.rs index f7ac924bb..c3870a3a9 100644 --- a/compiler/src/compile.rs +++ b/compiler/src/compile.rs @@ -1702,6 +1702,10 @@ impl Compiler { let mut loop_labels = vec![]; for generator in generators { + if generator.is_async { + unimplemented!("async for comprehensions"); + } + if loop_labels.is_empty() { // Load iterator onto stack (passed as first argument): self.emit(Instruction::LoadName { diff --git a/examples/parse_folder.rs b/examples/parse_folder.rs index 9bd3d05ae..513333b95 100644 --- a/examples/parse_folder.rs +++ b/examples/parse_folder.rs @@ -14,7 +14,8 @@ extern crate log; use clap::{App, Arg}; use rustpython_parser::{ast, parser}; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::time::Instant; fn main() { env_logger::init(); @@ -32,14 +33,21 @@ fn main() { let folder = Path::new(matches.value_of("folder").unwrap()); if folder.exists() && folder.is_dir() { println!("Parsing folder of python code: {:?}", folder); - let res = parse_folder(&folder).unwrap(); - println!("Processed {:?} files", res.len()); + let t1 = Instant::now(); + let parsed_files = parse_folder(&folder).unwrap(); + let t2 = Instant::now(); + let results = ScanResult { + t1, + t2, + parsed_files, + }; + statistics(results); } else { println!("{:?} is not a folder.", folder); } } -fn parse_folder(path: &Path) -> std::io::Result> { +fn parse_folder(path: &Path) -> std::io::Result> { let mut res = vec![]; info!("Parsing folder of python code: {:?}", path); for entry in path.read_dir()? { @@ -49,22 +57,66 @@ fn parse_folder(path: &Path) -> std::io::Result> { let path = entry.path(); if metadata.is_dir() { - let x = parse_folder(&path)?; - res.extend(x); + res.extend(parse_folder(&path)?); } if metadata.is_file() && path.extension().and_then(|s| s.to_str()) == Some("py") { - match parse_python_file(&path) { - Ok(x) => res.push(x), + let result = parse_python_file(&path); + match &result { + Ok(_) => {} Err(y) => error!("Erreur in file {:?} {:?}", path, y), } + res.push(ParsedFile { + filename: Box::new(path), + result, + }); } } Ok(res) } -fn parse_python_file(filename: &Path) -> Result { +fn parse_python_file(filename: &Path) -> ParseResult { info!("Parsing file {:?}", filename); let source = std::fs::read_to_string(filename).map_err(|e| e.to_string())?; parser::parse_program(&source).map_err(|e| e.to_string()) } + +fn statistics(results: ScanResult) { + // println!("Processed {:?} files", res.len()); + println!("Scanned a total of {} files", results.parsed_files.len()); + let total = results.parsed_files.len(); + let failed = results + .parsed_files + .iter() + .filter(|p| p.result.is_err()) + .count(); + let passed = results + .parsed_files + .iter() + .filter(|p| p.result.is_ok()) + .count(); + println!("Passed: {} Failed: {} Total: {}", passed, failed, total); + println!( + "That is {} % success rate.", + (passed as f64 * 100.0) / total as f64 + ); + let duration = results.t2 - results.t1; + println!("Total time spend: {:?}", duration); + println!( + "File processing rate: {} files/second", + (total * 1_000_000) as f64 / duration.as_micros() as f64 + ); +} + +struct ScanResult { + t1: Instant, + t2: Instant, + parsed_files: Vec, +} + +struct ParsedFile { + filename: Box, + result: ParseResult, +} + +type ParseResult = Result; diff --git a/parser/src/ast.rs b/parser/src/ast.rs index dcded9fc9..b11e0f9c6 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -318,6 +318,7 @@ pub struct Comprehension { pub target: Expression, pub iter: Expression, pub ifs: Vec, + pub is_async: bool, } #[derive(Debug, PartialEq)] diff --git a/parser/src/parser.rs b/parser/src/parser.rs index e5287f8d8..d27fce025 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -386,6 +386,7 @@ mod tests { target: mk_ident("y", 1, 8), iter: mk_ident("z", 1, 13), ifs: vec![], + is_async: false, }], } } @@ -415,6 +416,7 @@ mod tests { }, iter: mk_ident("z", 1, 17), ifs: vec![], + is_async: false, }, ast::Comprehension { location: ast::Location::new(1, 19), @@ -436,6 +438,7 @@ mod tests { }, }, ], + is_async: false, } ], } diff --git a/parser/src/python.lalrpop b/parser/src/python.lalrpop index 20b4a4168..30831c9fc 100644 --- a/parser/src/python.lalrpop +++ b/parser/src/python.lalrpop @@ -908,6 +908,7 @@ Atom: ast::Expression = { node: ast::ExpressionType::Tuple { elements: Vec::new() } }) }, + "(" ")" => e, "(" ")" => { ast::Expression { location, @@ -1021,8 +1022,9 @@ StarExpr: ast::Expression = { CompFor: Vec = => c; SingleForComprehension: ast::Comprehension = { - "for" "in" => { - ast::Comprehension { location, target, iter, ifs } + "for" "in" => { + let is_async = is_async.is_some(); + ast::Comprehension { location, target, iter, ifs, is_async } } }; diff --git a/tests/snippets/generators.py b/tests/snippets/generators.py index 3b7dc77c3..ddab1d68d 100644 --- a/tests/snippets/generators.py +++ b/tests/snippets/generators.py @@ -64,3 +64,26 @@ assert next(g) == 1 with assertRaises(KeyError): assert g.throw(KeyError, KeyError(), None) == 2 + + +r = [] +def p(a, b, c): + # print(a, b, c) + r.append(a) + r.append(b) + r.append(c) + + +def g5(): + p('a', (yield 2), (yield 5)) + yield 99 + +g = g5() +g.send(None) +g.send(66) +# g.send(88) +l = list(g) +# print(r) +# print(l) +assert l == [99] +assert r == ['a', 66, None] diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 138b11c6b..9543d5ce1 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -579,6 +579,7 @@ fn comprehension_to_ast( target => expression_to_ast(vm, &comprehension.target)?, iter => expression_to_ast(vm, &comprehension.iter)?, ifs => expressions_to_ast(vm, &comprehension.ifs)?, + is_async => vm.new_bool(comprehension.is_async), })) }