// This test does the following for every file in the rust-lang/rust repo: // // 1. Parse the file using syn into a syn::File. // 2. Extract every syn::Expr from the file. // 3. Print each expr to a string of source code. // 4. Parse the source code using librustc_parse into a rustc_ast::Expr. // 5. For both the syn::Expr and rustc_ast::Expr, crawl the syntax tree to // insert parentheses surrounding every subexpression. // 6. Serialize the fully parenthesized syn::Expr to a string of source code. // 7. Parse the fully parenthesized source code using librustc_parse. // 8. Compare the rustc_ast::Expr resulting from parenthesizing using rustc data // structures vs syn data structures, ignoring spans. If they agree, rustc's // parser and syn's parser have identical handling of expression precedence.
usecrate::common::eq::SpanlessEq; usecrate::common::parse; use quote::ToTokens; use rustc_ast::ast; use rustc_ast::ptr::P; use rustc_ast_pretty::pprust; use rustc_span::edition::Edition; use std::fs; use std::path::Path; use std::process; use std::sync::atomic::{AtomicUsize, Ordering}; use syn::parse::Parser as _;
#[macro_use] mod macros;
mod common; mod repo;
#[path = "../src/scan_expr.rs"] mod scan_expr;
#[test] fn test_rustc_precedence() {
repo::rayon_init();
repo::clone_rust(); let abort_after = repo::abort_after(); if abort_after == 0 {
panic!("skipping all precedence tests");
}
let passed = AtomicUsize::new(0); let failed = AtomicUsize::new(0);
repo::for_each_rust_file(|path| { let content = fs::read_to_string(path).unwrap();
let (l_passed, l_failed) = match syn::parse_file(&content) {
Ok(file) => { let edition = repo::edition(path).parse().unwrap(); let exprs = collect_exprs(file); let (l_passed, l_failed) = test_expressions(path, edition, exprs);
errorf!( "=== {}: {} passed | {} failed\n",
path.display(),
l_passed,
l_failed,
);
(l_passed, l_failed)
}
Err(msg) => {
errorf!("\nFAIL {} - syn failed to parse: {}\n", path.display(), msg);
(0, 1)
}
};
passed.fetch_add(l_passed, Ordering::Relaxed); let prev_failed = failed.fetch_add(l_failed, Ordering::Relaxed);
if prev_failed + l_failed >= abort_after {
process::exit(1);
}
});
let passed = passed.into_inner(); let failed = failed.into_inner();
fn librustc_parenthesize(mut librustc_expr: P<ast::Expr>) -> P<ast::Expr> { use rustc_ast::ast::{
AssocItem, AssocItemKind, Attribute, BinOpKind, Block, BoundConstness, Expr, ExprField,
ExprKind, GenericArg, GenericBound, Local, LocalKind, Pat, PolyTraitRef, Stmt, StmtKind,
StructExpr, StructRest, TraitBoundModifiers, Ty,
}; use rustc_ast::mut_visit::{walk_flat_map_item, MutVisitor}; use rustc_ast::visit::{AssocCtxt, BoundKind}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_span::DUMMY_SP; use smallvec::SmallVec; use std::mem; use std::ops::DerefMut; use thin_vec::ThinVec;
// We don't want to look at expressions that might appear in patterns or // types yet. We'll look into comparing those in the future. For now // focus on expressions appearing in other places. fn visit_pat(&mutself, pat: &mut P<Pat>) { let _ = pat;
}
fn fold_meta_name_value(&mutself, meta: MetaNameValue) -> MetaNameValue { // Don't turn #[p = "..."] into #[p = ("...")].
meta
}
// We don't want to look at expressions that might appear in patterns or // types yet. We'll look into comparing those in the future. For now // focus on expressions appearing in other places. fn fold_pat(&mutself, pat: Pat) -> Pat {
pat
}
/// Walk through a crate collecting all expressions we can find in it. fn collect_exprs(file: syn::File) -> Vec<syn::Expr> { use syn::fold::Fold; use syn::punctuated::Punctuated; use syn::{token, ConstParam, Expr, ExprTuple, Pat, Path};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.