From cd43387b0abb6fcb2e1ef3d1a1e79854baef14f0 Mon Sep 17 00:00:00 2001 From: Kevin Mehall Date: Sun, 19 Jul 2020 19:45:33 -0600 Subject: [PATCH] Reformat with `cargo fmt` --- benches/expr.rs | 10 +- benches/json.rs | 10 +- peg-macros/analysis.rs | 57 ++++---- peg-macros/ast.rs | 24 ++-- peg-macros/bin.rs | 57 ++++---- peg-macros/lib.rs | 10 +- peg-macros/tokens.rs | 69 +++++---- peg-macros/translate.rs | 307 ++++++++++++++++++++++++---------------- peg-runtime/error.rs | 18 ++- peg-runtime/lib.rs | 7 +- peg-runtime/slice.rs | 16 ++- peg-runtime/str.rs | 22 +-- src/lib.rs | 36 ++--- tests/trybuild.rs | 6 +- 14 files changed, 382 insertions(+), 267 deletions(-) diff --git a/benches/expr.rs b/benches/expr.rs index 4f5fa19..84b3ea5 100644 --- a/benches/expr.rs +++ b/benches/expr.rs @@ -23,10 +23,10 @@ rule atom() = ['0'..='9']+ / "(" expr() ")" #[bench] fn expr(b: &mut Bencher) { - let bench_str = "1+2+3+4*5*6^7^8^(0^1*2+1)"; + let bench_str = "1+2+3+4*5*6^7^8^(0^1*2+1)"; - b.bytes = bench_str.len() as u64; - b.iter(|| { - parser::expr(bench_str).unwrap(); - }); + b.bytes = bench_str.len() as u64; + b.iter(|| { + parser::expr(bench_str).unwrap(); + }); } diff --git a/benches/json.rs b/benches/json.rs index 3751f05..398d85d 100644 --- a/benches/json.rs +++ b/benches/json.rs @@ -45,7 +45,7 @@ rule string() #[bench] fn json(b: &mut Bencher) { - let bench_str = r#" + let bench_str = r#" { "X": 0.6e2, "Y": 5, @@ -69,8 +69,8 @@ fn json(b: &mut Bencher) { } "#; - b.bytes = bench_str.len() as u64; - b.iter(|| { - parser::json(bench_str).unwrap(); - }); + b.bytes = bench_str.len() as u64; + b.iter(|| { + parser::json(bench_str).unwrap(); + }); } diff --git a/peg-macros/analysis.rs b/peg-macros/analysis.rs index e22a495..8aec9e2 100644 --- a/peg-macros/analysis.rs +++ b/peg-macros/analysis.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use proc_macro2::Span; +use std::collections::HashMap; use crate::ast::*; @@ -14,10 +14,13 @@ pub fn check<'a>(grammar: &'a Grammar) -> GrammarAnalysis<'a> { for rule in grammar.iter_rules() { rules.entry(rule.name.to_string()).or_insert(rule); } - - let left_recursion = RecursionVisitor::check(grammar, &rules); - GrammarAnalysis { rules, left_recursion } + let left_recursion = RecursionVisitor::check(grammar, &rules); + + GrammarAnalysis { + rules, + left_recursion, + } } struct RecursionVisitor<'a> { @@ -33,7 +36,10 @@ pub struct RecursionError { impl RecursionError { pub fn msg(&self) -> String { - format!("left recursive rules create an infinite loop: {}", self.path.join(" -> ")) + format!( + "left recursive rules create an infinite loop: {}", + self.path.join(" -> ") + ) } } @@ -45,7 +51,6 @@ struct RuleInfo { nullable: bool, } - impl<'a> RecursionVisitor<'a> { fn check(grammar: &'a Grammar, rules: &HashMap) -> Vec { let mut visitor = RecursionVisitor { @@ -75,10 +80,17 @@ impl<'a> RecursionVisitor<'a> { RuleExpr(ref rule_ident, _) => { let name = rule_ident.to_string(); - if let Some(loop_start) = self.stack.iter().position(|caller_name| { caller_name == &name}) { + if let Some(loop_start) = self + .stack + .iter() + .position(|caller_name| caller_name == &name) + { let mut recursive_loop = self.stack[loop_start..].to_vec(); recursive_loop.push(name); - self.errors.push(RecursionError { path: recursive_loop, span: rule_ident.span()}); + self.errors.push(RecursionError { + path: recursive_loop, + span: rule_ident.span(), + }); return RuleInfo { nullable: false }; } @@ -92,10 +104,10 @@ impl<'a> RecursionVisitor<'a> { ActionExpr(ref elems, ..) => { for elem in elems { if !self.walk_expr(&elem.expr).nullable { - return RuleInfo { nullable: false } + return RuleInfo { nullable: false }; } } - + RuleInfo { nullable: true } } ChoiceExpr(ref choices) => { @@ -108,34 +120,31 @@ impl<'a> RecursionVisitor<'a> { RuleInfo { nullable } } - OptionalExpr(ref expr) | - PosAssertExpr(ref expr) | - NegAssertExpr(ref expr) => { + OptionalExpr(ref expr) | PosAssertExpr(ref expr) | NegAssertExpr(ref expr) => { self.walk_expr(expr); RuleInfo { nullable: true } } - Repeat(ref expr, ref bounds, _) => { + Repeat(ref expr, ref bounds, _) => { let nullable = match bounds { BoundedRepeat::None => true, _ => false, }; let res = self.walk_expr(expr); - RuleInfo { nullable: res.nullable | nullable } + RuleInfo { + nullable: res.nullable | nullable, + } } - MatchStrExpr(ref expr) | - QuietExpr(ref expr) => self.walk_expr(expr), + MatchStrExpr(ref expr) | QuietExpr(ref expr) => self.walk_expr(expr), - PrecedenceExpr{ .. } => { RuleInfo { nullable: false } }, + PrecedenceExpr { .. } => RuleInfo { nullable: false }, - | LiteralExpr(_) - | PatternExpr(_) - | MethodExpr(_, _) - | FailExpr(_) - | MarkerExpr(_) => { RuleInfo { nullable: false } } - PositionExpr => { RuleInfo { nullable: true} } + LiteralExpr(_) | PatternExpr(_) | MethodExpr(_, _) | FailExpr(_) | MarkerExpr(_) => { + RuleInfo { nullable: false } + } + PositionExpr => RuleInfo { nullable: true }, } } } diff --git a/peg-macros/ast.rs b/peg-macros/ast.rs index e57b676..e3f68c3 100644 --- a/peg-macros/ast.rs +++ b/peg-macros/ast.rs @@ -1,4 +1,4 @@ -use proc_macro2::{ TokenStream, Ident, Literal }; +use proc_macro2::{Ident, Literal, TokenStream}; #[derive(Debug)] pub struct Grammar { @@ -11,12 +11,10 @@ pub struct Grammar { } impl Grammar { - pub fn iter_rules(&self) -> impl Iterator { - self.items.iter().filter_map(|item| { - match item { - Item::Rule(r) => Some(r), - _ => None - } + pub fn iter_rules(&self) -> impl Iterator { + self.items.iter().filter_map(|item| match item { + Item::Rule(r) => Some(r), + _ => None, }) } } @@ -68,12 +66,18 @@ pub enum Expr { Repeat(Box, BoundedRepeat, /*sep*/ Option>), PosAssertExpr(Box), NegAssertExpr(Box), - ActionExpr(Vec, /*action*/ Option, /*cond*/ bool), + ActionExpr( + Vec, + /*action*/ Option, + /*cond*/ bool, + ), MatchStrExpr(Box), PositionExpr, QuietExpr(Box), FailExpr(Literal), - PrecedenceExpr{ levels: Vec }, + PrecedenceExpr { + levels: Vec, + }, MarkerExpr(bool), } @@ -100,4 +104,4 @@ pub enum BoundedRepeat { Plus, Exact(TokenStream), Both(Option, Option), -} \ No newline at end of file +} diff --git a/peg-macros/bin.rs b/peg-macros/bin.rs index cbcca8b..a66f4c5 100644 --- a/peg-macros/bin.rs +++ b/peg-macros/bin.rs @@ -1,13 +1,13 @@ //! Standalone version of rust-peg used for bootstrapping the meta-grammar -extern crate quote; -extern crate proc_macro2; extern crate proc_macro; +extern crate proc_macro2; +extern crate quote; use std::env; use std::fs::File; +use std::io::{stderr, stdin, stdout}; use std::io::{Read, Write}; -use std::io::{stdin, stdout, stderr}; use std::path::Path; use std::process; @@ -15,39 +15,42 @@ use std::process; // requires `::peg` paths. extern crate peg_runtime as peg; +mod analysis; mod ast; -mod tokens; mod grammar; +mod tokens; mod translate; -mod analysis; fn main() { - let args = env::args_os().collect::>(); - let progname = &args[0]; - let mut log = stderr(); - - let mut source = String::new(); - - if args.len() == 2 && &args[1] != "-h" { - File::open(Path::new(&args[1])).unwrap().read_to_string(&mut source).unwrap(); - } else if args.len() == 1 { - stdin().read_to_string(&mut source).unwrap(); - } else { - writeln!(log, "Usage: {} [file]", progname.to_string_lossy()).unwrap(); - process::exit(0); - } - - let source_tokens = source.parse().expect("Error tokenizing input"); - let input_tokens = tokens::FlatTokenStream::new(source_tokens); + let args = env::args_os().collect::>(); + let progname = &args[0]; + let mut log = stderr(); + + let mut source = String::new(); + + if args.len() == 2 && &args[1] != "-h" { + File::open(Path::new(&args[1])) + .unwrap() + .read_to_string(&mut source) + .unwrap(); + } else if args.len() == 1 { + stdin().read_to_string(&mut source).unwrap(); + } else { + writeln!(log, "Usage: {} [file]", progname.to_string_lossy()).unwrap(); + process::exit(0); + } + + let source_tokens = source.parse().expect("Error tokenizing input"); + let input_tokens = tokens::FlatTokenStream::new(source_tokens); let grammar = match grammar::peg::peg_grammar(&input_tokens) { Ok(g) => g, Err(err) => { eprintln!("Failed to parse grammar: expected {}", err.expected); - process::exit(1); + process::exit(1); } }; - let parser_tokens = translate::compile_grammar(&grammar); - let mut out = stdout(); - writeln!(&mut out, "// Generated by rust-peg. Do not edit.").unwrap(); - write!(&mut out, "{}", parser_tokens).unwrap(); + let parser_tokens = translate::compile_grammar(&grammar); + let mut out = stdout(); + writeln!(&mut out, "// Generated by rust-peg. Do not edit.").unwrap(); + write!(&mut out, "{}", parser_tokens).unwrap(); } diff --git a/peg-macros/lib.rs b/peg-macros/lib.rs index 12f0ec2..6393788 100644 --- a/peg-macros/lib.rs +++ b/peg-macros/lib.rs @@ -1,6 +1,6 @@ -extern crate quote; -extern crate proc_macro2; extern crate proc_macro; +extern crate proc_macro2; +extern crate quote; use quote::quote_spanned; @@ -8,14 +8,14 @@ use quote::quote_spanned; // requires `::peg` paths. extern crate peg_runtime as peg; +mod analysis; mod ast; -mod tokens; mod grammar; +mod tokens; mod translate; -mod analysis; /// The main macro for creating a PEG parser. -/// +/// /// For the grammar syntax, see the `peg` crate documentation. #[proc_macro] pub fn parser(input: proc_macro::TokenStream) -> proc_macro::TokenStream { diff --git a/peg-macros/tokens.rs b/peg-macros/tokens.rs index c618be8..bb59935 100644 --- a/peg-macros/tokens.rs +++ b/peg-macros/tokens.rs @@ -1,9 +1,9 @@ -use proc_macro2::{ TokenStream, TokenTree, Ident, Group, Punct, Literal, Delimiter, Span, Spacing }; -use peg::{RuleResult, Parse, ParseElem, ParseLiteral, ParseSlice}; +use peg::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult}; +use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; #[derive(Debug, Clone)] pub struct FlatTokenStream { - tokens: Vec + tokens: Vec, } #[derive(Debug, Clone)] @@ -12,7 +12,7 @@ pub enum Token { Literal(Literal), Punct(Punct), Begin(Group, usize), - End(Delimiter, Span) + End(Delimiter, Span), } impl FlatTokenStream { @@ -46,25 +46,29 @@ impl FlatTokenStream { FlatTokenStream { tokens } } - pub fn len(&self) -> usize { self.tokens.len() } //TODO + pub fn len(&self) -> usize { + self.tokens.len() + } //TODO pub fn ident(&self, pos: usize) -> RuleResult { match self.tokens.get(pos) { - Some(Token::Ident(i)) => RuleResult::Matched(pos+1, i.clone()), + Some(Token::Ident(i)) => RuleResult::Matched(pos + 1, i.clone()), _ => RuleResult::Failed, } } pub fn literal(&self, pos: usize) -> RuleResult { match self.tokens.get(pos) { - Some(Token::Literal(i)) => RuleResult::Matched(pos+1, i.clone()), + Some(Token::Literal(i)) => RuleResult::Matched(pos + 1, i.clone()), _ => RuleResult::Failed, } } pub fn group(&self, pos: usize, delim: Delimiter) -> RuleResult { match self.tokens.get(pos) { - Some(Token::Begin(g, n)) if g.delimiter() == delim => RuleResult::Matched(*n, g.stream()), + Some(Token::Begin(g, n)) if g.delimiter() == delim => { + RuleResult::Matched(*n, g.stream()) + } _ => RuleResult::Failed, } } @@ -100,16 +104,21 @@ impl ::std::fmt::Display for Sp { impl Parse for FlatTokenStream { type PositionRepr = Sp; - fn start(&self) -> usize { 0 } + fn start(&self) -> usize { + 0 + } fn position_repr(&self, pos: usize) -> Sp { - Sp(match &self.tokens[pos] { - Token::Ident(i) => i.span(), - Token::Literal(l) => l.span(), - Token::Punct(p) => p.span(), - Token::Begin(g, _) => g.span(), - Token::End(_, span) => span.clone() - }, pos) + Sp( + match &self.tokens[pos] { + Token::Ident(i) => i.span(), + Token::Literal(l) => l.span(), + Token::Punct(p) => p.span(), + Token::Begin(g, _) => g.span(), + Token::End(_, span) => span.clone(), + }, + pos, + ) } } @@ -119,7 +128,7 @@ impl ParseElem for FlatTokenStream { fn parse_elem(&self, pos: usize) -> RuleResult { match self.tokens.get(pos) { Some(c) => RuleResult::Matched(pos + 1, c.clone()), - None => RuleResult::Failed + None => RuleResult::Failed, } } } @@ -129,7 +138,7 @@ fn delimiter_start(d: Delimiter) -> &'static str { Delimiter::Brace => "{", Delimiter::Bracket => "[", Delimiter::Parenthesis => "(", - _ => "" + _ => "", } } @@ -138,7 +147,7 @@ fn delimiter_end(d: Delimiter) -> &'static str { Delimiter::Brace => "}", Delimiter::Bracket => "]", Delimiter::Parenthesis => ")", - _ => "" + _ => "", } } @@ -150,14 +159,18 @@ impl ParseLiteral for FlatTokenStream { if literal.len() == 1 { RuleResult::Matched(pos + 1, ()) } else if p.spacing() == Spacing::Joint { - self.parse_string_literal(pos+1, &literal[1..]) + self.parse_string_literal(pos + 1, &literal[1..]) } else { RuleResult::Failed } - }, - Some(Token::Begin(g, _)) if delimiter_start(g.delimiter()) == literal => RuleResult::Matched(pos + 1, ()), - Some(Token::End(d, _)) if delimiter_end(*d) == literal => RuleResult::Matched(pos + 1, ()), - _ => RuleResult::Failed + } + Some(Token::Begin(g, _)) if delimiter_start(g.delimiter()) == literal => { + RuleResult::Matched(pos + 1, ()) + } + Some(Token::End(d, _)) if delimiter_end(*d) == literal => { + RuleResult::Matched(pos + 1, ()) + } + _ => RuleResult::Failed, } } } @@ -170,11 +183,11 @@ impl<'input> ParseSlice<'input> for FlatTokenStream { while pos < p2 { let (t, next_pos): (TokenTree, usize) = match &self.tokens[pos] { - Token::Ident(i) => (i.clone().into(), pos+1), - Token::Literal(l) => (l.clone().into(), pos+1), - Token::Punct(p) => (p.clone().into(), pos+1), + Token::Ident(i) => (i.clone().into(), pos + 1), + Token::Literal(l) => (l.clone().into(), pos + 1), + Token::Punct(p) => (p.clone().into(), pos + 1), Token::Begin(g, end) => (g.clone().into(), *end), - Token::End(..) => panic!("$-expr containing unmatched group end") + Token::End(..) => panic!("$-expr containing unmatched group end"), }; ts.extend(Some(t)); pos = next_pos; diff --git a/peg-macros/translate.rs b/peg-macros/translate.rs index 4afa32d..82e3ec2 100644 --- a/peg-macros/translate.rs +++ b/peg-macros/translate.rs @@ -1,11 +1,11 @@ -use std::collections::{ HashMap, HashSet }; use proc_macro2::{Ident, Span, TokenStream}; +use std::collections::{HashMap, HashSet}; -use quote::{quote, quote_spanned, format_ident}; +use quote::{format_ident, quote, quote_spanned}; pub use self::Expr::*; -use crate::ast::*; use crate::analysis; +use crate::ast::*; pub fn report_error(span: Span, msg: String) -> TokenStream { quote_spanned!(span=>compile_error!(#msg);) @@ -17,16 +17,20 @@ pub fn report_error_expr(span: Span, msg: String) -> TokenStream { } fn extra_args_def(grammar: &Grammar) -> TokenStream { - let args: Vec = grammar.args.iter().map(|&(ref name, ref tp)| { - quote!(, #name: #tp) - }).collect(); + let args: Vec = grammar + .args + .iter() + .map(|&(ref name, ref tp)| quote!(, #name: #tp)) + .collect(); quote!(#(#args)*) } fn extra_args_call(grammar: &Grammar) -> TokenStream { - let args: Vec = grammar.args.iter().map(|&(ref name, _)| { - quote!(, #name) - }).collect(); + let args: Vec = grammar + .args + .iter() + .map(|&(ref name, _)| quote!(, #name)) + .collect(); quote!(#(#args)*) } @@ -59,16 +63,20 @@ pub(crate) fn compile_grammar(grammar: &Grammar) -> TokenStream { Item::Rule(rule) => { if seen_rule_names.insert(rule.name.to_string()) { if rule.cached && !(rule.params.is_empty() && rule.ty_params.is_none()) { - items.push(report_error(rule.name.span(), format!("rules with arguments cannot use #[cache]"))); + items.push(report_error( + rule.name.span(), + format!("rules with arguments cannot use #[cache]"), + )); } if rule.visibility.is_some() { for param in &rule.params { match ¶m.ty { - RuleParamTy::Rule(..) => items.push( - report_error(param.name.span(), format!("parameters on `pub rule` must be Rust types")) - ), - _ => {} + RuleParamTy::Rule(..) => items.push(report_error( + param.name.span(), + format!("parameters on `pub rule` must be Rust types"), + )), + _ => {} } } @@ -77,11 +85,13 @@ pub(crate) fn compile_grammar(grammar: &Grammar) -> TokenStream { items.push(compile_rule(context, rule)); } else { - items.push(report_error(rule.name.span(), format!("duplicate rule `{}`", rule.name))); + items.push(report_error( + rule.name.span(), + format!("duplicate rule `{}`", rule.name), + )); } } } - } let doc = &grammar.doc; @@ -115,7 +125,9 @@ fn make_parse_state(grammar: &Grammar) -> TokenStream { if rule.cached { let name = format_ident!("{}_cache", rule.name); let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(())); - cache_fields_def.push(quote!{ #name: ::std::collections::HashMap> }); + cache_fields_def.push( + quote! { #name: ::std::collections::HashMap> }, + ); cache_fields.push(name); } } @@ -153,17 +165,19 @@ fn compile_rule(context: &Context, rule: &Rule) -> TokenStream { let ref rule_name = rule.name; let name = format_ident!("__parse_{}", rule.name); let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(())); - let result_used = rule.ret_type.is_some(); + let result_used = rule.ret_type.is_some(); let ty_params = rule.ty_params.as_ref().map(|x| &x[..]).unwrap_or(&[]); let mut context = context.clone(); - context.rules_from_args.extend(rule.params.iter().map(|param| { param.name.to_string() })); + context + .rules_from_args + .extend(rule.params.iter().map(|param| param.name.to_string())); let body = compile_expr(&context, &rule.expr, result_used); let wrapped_body = if cfg!(feature = "trace") { let str_rule_name = rule_name.to_string(); - quote!{{ + quote! {{ let loc = ::peg::Parse::position_repr(__input, __pos); println!("[PEG_TRACE] Attempting to match rule `{}` at {}", #str_rule_name, loc); let __peg_result: ::peg::RuleResult<#ret_ty> = {#body}; @@ -179,7 +193,9 @@ fn compile_rule(context: &Context, rule: &Rule) -> TokenStream { } } }} - } else { body }; + } else { + body + }; let extra_args_def = &context.extra_args_def; @@ -190,7 +206,7 @@ fn compile_rule(context: &Context, rule: &Rule) -> TokenStream { let cache_trace = if cfg!(feature = "trace") { let str_rule_name = rule.name.to_string(); - quote!{ + quote! { let loc = ::peg::Parse::position_repr(__input, __pos); match &entry { &::peg::RuleResult::Matched(..) => println!("[PEG_TRACE] Cached match of rule {} at {}", #str_rule_name, loc), @@ -231,10 +247,14 @@ fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream { let parse_fn = format_ident!("__parse_{}", rule.name.to_string(), span = name.span()); let ty_params = rule.ty_params.as_ref().map(|x| &x[..]).unwrap_or(&[]); let rule_params = rule_params_list(rule); - let rule_params_call: Vec = rule.params.iter().map(|param| { - let param_name = ¶m.name; - quote!(#param_name) - }).collect(); + let rule_params_call: Vec = rule + .params + .iter() + .map(|param| { + let param_name = ¶m.name; + quote!(#param_name) + }) + .collect(); let extra_args_def = &context.extra_args_def; let extra_args_call = &context.extra_args_call; @@ -279,11 +299,11 @@ fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream { fn name_or_ignore(n: Option<&Ident>) -> TokenStream { match n { Some(n) => quote!(#n), - None => quote!(_) + None => quote!(_), } } -fn ordered_choice(mut rs: impl DoubleEndedIterator) -> TokenStream { +fn ordered_choice(mut rs: impl DoubleEndedIterator) -> TokenStream { rs.next_back().map(|last| rs.rfold(last, |fallback, preferred| { quote! {{ let __choice_res = #preferred; @@ -302,13 +322,13 @@ fn labeled_seq(context: &Context, exprs: &[TaggedExpr], inner: TokenStream) -> T let seq_res = compile_expr(context, &expr.expr, value_name.is_some()); - quote!{{ + quote! {{ let __seq_res = #seq_res; match __seq_res { ::peg::RuleResult::Matched(__pos, #name_pat) => { #then } ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, } - }} + }} }) } @@ -325,7 +345,7 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { match e { LiteralExpr(ref s) => { let escaped_str = s.to_string(); - quote!{ match ::peg::ParseLiteral::parse_string_literal(__input, __pos, #s) { + quote! { match ::peg::ParseLiteral::parse_string_literal(__input, __pos, #s) { ::peg::RuleResult::Matched(__pos, __val) => ::peg::RuleResult::Matched(__pos, __val), ::peg::RuleResult::Failed => __err_state.mark_failure(__pos, #escaped_str) }} @@ -335,30 +355,38 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { let invert = false; let pat_str = pattern.to_string(); - let (in_set, not_in_set) = cond_swap(invert, ( - quote!{ ::peg::RuleResult::Matched(__next, ()) }, - quote!{ __err_state.mark_failure(__pos, #pat_str) }, - )); + let (in_set, not_in_set) = cond_swap( + invert, + ( + quote! { ::peg::RuleResult::Matched(__next, ()) }, + quote! { __err_state.mark_failure(__pos, #pat_str) }, + ), + ); let in_set_arm = quote!( #pattern => #in_set, ); - quote!{ + quote! { match ::peg::ParseElem::parse_elem(__input, __pos) { ::peg::RuleResult::Matched(__next, __ch) => match __ch { #in_set_arm _ => #not_in_set, } ::peg::RuleResult::Failed => __err_state.mark_failure(__pos, #pat_str) - } + } } } - RuleExpr(ref rule_name, ref rule_args) if context.rules_from_args.contains(&rule_name.to_string()) => { + RuleExpr(ref rule_name, ref rule_args) + if context.rules_from_args.contains(&rule_name.to_string()) => + { if !rule_args.is_empty() { - return report_error_expr(rule_name.span(), format!("rule closure does not accept arguments")); + return report_error_expr( + rule_name.span(), + format!("rule closure does not accept arguments"), + ); } - quote!{ #rule_name(__input, __state, __err_state, __pos) } + quote! { #rule_name(__input, __state, __err_state, __pos) } } RuleExpr(ref rule_name, ref rule_args) => { @@ -367,51 +395,74 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { let rule_def = if let Some(rule_def) = context.rules.get(&rule_name_str) { rule_def } else { - return report_error_expr(rule_name.span(), format!("undefined rule `{}`", rule_name_str)); + return report_error_expr( + rule_name.span(), + format!("undefined rule `{}`", rule_name_str), + ); }; if result_used && rule_def.ret_type.is_none() { - let msg = format!("using result of rule `{}`, which does not return a value", rule_name_str); + let msg = format!( + "using result of rule `{}`, which does not return a value", + rule_name_str + ); return report_error_expr(rule_name.span(), msg); } if rule_def.params.len() != rule_args.len() { - return report_error_expr(rule_name.span(), - format!("this rule takes {} parameters but {} parameters were supplied", rule_def.params.len(), rule_args.len())); + return report_error_expr( + rule_name.span(), + format!( + "this rule takes {} parameters but {} parameters were supplied", + rule_def.params.len(), + rule_args.len() + ), + ); } for (param, arg) in rule_def.params.iter().zip(rule_args.iter()) { match (¶m.ty, &arg) { (RuleParamTy::Rust(..), RuleArg::Peg(..)) => { - return report_error_expr(rule_name.span(), - format!("parameter `{}` expects a value, but a PEG expression was passed", param.name)); + return report_error_expr( + rule_name.span(), + format!( + "parameter `{}` expects a value, but a PEG expression was passed", + param.name + ), + ); } (RuleParamTy::Rule(..), RuleArg::Rust(..)) => { - return report_error_expr(rule_name.span(), - format!("parameter `{}` expects a PEG expression, but a value was passed", param.name)); - }, + return report_error_expr( + rule_name.span(), + format!( + "parameter `{}` expects a PEG expression, but a value was passed", + param.name + ), + ); + } (RuleParamTy::Rule(..), RuleArg::Peg(..)) => (), (RuleParamTy::Rust(..), RuleArg::Rust(..)) => (), } } - let func = format_ident!("__parse_{}", rule_name, span=rule_name.span()); + let func = format_ident!("__parse_{}", rule_name, span = rule_name.span()); let extra_args_call = &context.extra_args_call; - let rule_args_call: Vec = rule_args.iter().map(|arg| { - match arg { + let rule_args_call: Vec = rule_args + .iter() + .map(|arg| match arg { RuleArg::Peg(e) => { let expr = compile_expr(context, e, true); - quote!{ |__input, __state, __err_state, __pos| { #expr } } + quote! { |__input, __state, __err_state, __pos| { #expr } } } RuleArg::Rust(e) => e.clone(), - } - }).collect(); + }) + .collect(); if result_used { - quote!{ #func(__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*) } + quote! { #func(__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*) } } else { - quote!{ + quote! { match #func(__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*){ ::peg::RuleResult::Matched(pos, _) => ::peg::RuleResult::Matched(pos, ()), ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, @@ -421,25 +472,27 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { } MethodExpr(ref method, ref args) => { - quote!{ __input.#method(__pos, #args) } + quote! { __input.#method(__pos, #args) } } - ChoiceExpr(ref exprs) => { - ordered_choice(exprs.iter().map(|expr| compile_expr(context, expr, result_used))) - } + ChoiceExpr(ref exprs) => ordered_choice( + exprs + .iter() + .map(|expr| compile_expr(context, expr, result_used)), + ), OptionalExpr(ref e) => { let optional_res = compile_expr(context, e, result_used); if result_used { - quote!{ + quote! { match #optional_res { ::peg::RuleResult::Matched(__newpos, __value) => { ::peg::RuleResult::Matched(__newpos, Some(__value)) }, ::peg::RuleResult::Failed => { ::peg::RuleResult::Matched(__pos, None) }, } } } else { - quote!{ + quote! { match #optional_res { ::peg::RuleResult::Matched(__newpos, _) => { ::peg::RuleResult::Matched(__newpos, ()) }, ::peg::RuleResult::Failed => { ::peg::RuleResult::Matched(__pos, ()) }, @@ -455,7 +508,7 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { BoundedRepeat::None => (None, None), BoundedRepeat::Plus => (Some(quote!(1)), None), BoundedRepeat::Exact(ref code) => (Some(code.clone()), Some(code.clone())), - BoundedRepeat::Both(ref min, ref max) => (min.clone(), max.clone()) + BoundedRepeat::Both(ref min, ref max) => (min.clone(), max.clone()), }; let match_sep = if let Some(sep) = sep { @@ -469,26 +522,32 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { } }; } - } else { quote!() }; + } else { + quote!() + }; let result = if result_used { - quote!( __repeat_value ) + quote!(__repeat_value) } else { - quote!( () ) + quote!(()) }; let (repeat_vec, repeat_step) = - if result_used || min.is_some() || max.is_some() || sep.is_some() { - (Some(quote! { let mut __repeat_value = vec!(); }), - Some(quote! { __repeat_value.push(__value); })) - } else { - (None, None) - }; + if result_used || min.is_some() || max.is_some() || sep.is_some() { + ( + Some(quote! { let mut __repeat_value = vec!(); }), + Some(quote! { __repeat_value.push(__value); }), + ) + } else { + (None, None) + }; - let max_check = max.map(|max| { quote! { if __repeat_value.len() >= #max { break } }}); + let max_check = max.map(|max| { + quote! { if __repeat_value.len() >= #max { break } } + }); let result_check = if let Some(min) = min { - quote!{ + quote! { if __repeat_value.len() >= #min { ::peg::RuleResult::Matched(__repeat_pos, #result) } else { @@ -496,10 +555,10 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { } } } else { - quote!{ ::peg::RuleResult::Matched(__repeat_pos, #result) } + quote! { ::peg::RuleResult::Matched(__repeat_pos, #result) } }; - quote!{{ + quote! {{ let mut __repeat_pos = __pos; #repeat_vec @@ -551,23 +610,21 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { }} } - ActionExpr(ref exprs, ref code, is_cond) => { - labeled_seq(context, &exprs, { - if *is_cond { - quote!{ - match { #code } { - Ok(res) => ::peg::RuleResult::Matched(__pos, res), - Err(expected) => { - __err_state.mark_failure(__pos, expected); - ::peg::RuleResult::Failed - }, - } + ActionExpr(ref exprs, ref code, is_cond) => labeled_seq(context, &exprs, { + if *is_cond { + quote! { + match { #code } { + Ok(res) => ::peg::RuleResult::Matched(__pos, res), + Err(expected) => { + __err_state.mark_failure(__pos, expected); + ::peg::RuleResult::Failed + }, } - } else { - quote!{ ::peg::RuleResult::Matched(__pos, { #code }) } } - }) - } + } else { + quote! { ::peg::RuleResult::Matched(__pos, { #code }) } + } + }), MatchStrExpr(ref expr) => { let inner = compile_expr(context, expr, false); quote! {{ @@ -591,10 +648,10 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { }} } FailExpr(ref expected) => { - quote!{{ __err_state.mark_failure(__pos, #expected); ::peg::RuleResult::Failed }} + quote! {{ __err_state.mark_failure(__pos, #expected); ::peg::RuleResult::Failed }} } - - PrecedenceExpr{ ref levels } => { + + PrecedenceExpr { ref levels } => { let mut pre_rules = Vec::new(); let mut level_code = Vec::new(); let mut span_capture = None; @@ -616,27 +673,35 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { let r_arg = name_or_ignore(right_arg.name.as_ref()); let action = &op.action; - let action = if let Some((lpos_name, val_name, rpos_name, wrap_action)) = &span_capture { + let action = if let Some((lpos_name, val_name, rpos_name, wrap_action)) = + &span_capture + { quote!((|#lpos_name, #val_name, #rpos_name| {#wrap_action})(__lpos, #action, __pos)) } else { quote!({#action}) }; match (&left_arg.expr, &right_arg.expr) { - (&PositionExpr, &PositionExpr) if op.elements.len() == 3 => { // wrapper rule to capture expression span + (&PositionExpr, &PositionExpr) if op.elements.len() == 3 => { + // wrapper rule to capture expression span match &op.elements[1].expr { &MarkerExpr(..) => (), - _ => return quote!(compile_error!("span capture rule must be `l:position!() n:@ r:position!()")) + _ => { + return quote!(compile_error!( + "span capture rule must be `l:position!() n:@ r:position!()" + )) + } } span_capture = Some(( name_or_ignore(op.elements[0].name.as_ref()), name_or_ignore(op.elements[1].name.as_ref()), name_or_ignore(op.elements[2].name.as_ref()), - &op.action + &op.action, )); } - (&MarkerExpr(la), &MarkerExpr(ra)) if op.elements.len() >= 3 => { //infix + (&MarkerExpr(la), &MarkerExpr(ra)) if op.elements.len() >= 3 => { + //infix let new_prec = match (la, ra) { (true, false) => prec + 1, // left associative (false, true) => prec, // right associative @@ -655,18 +720,22 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { }) ); } - (&MarkerExpr(_), _) if op.elements.len() >= 2 => { // postfix - post_rules.push( - labeled_seq(context, &op.elements[1..op.elements.len()], { - quote!{ + (&MarkerExpr(_), _) if op.elements.len() >= 2 => { + // postfix + post_rules.push(labeled_seq( + context, + &op.elements[1..op.elements.len()], + { + quote! { let #l_arg = __infix_result; __infix_result = #action; ::peg::RuleResult::Matched(__pos, ()) } - }) - ); + }, + )); } - (_, &MarkerExpr(a)) if op.elements.len() >= 2 => { // prefix + (_, &MarkerExpr(a)) if op.elements.len() >= 2 => { + // prefix let new_prec = match a { true => prec, false => prec + 1, @@ -681,18 +750,17 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { }) ); } - _ => { // atom - pre_rules.push( - labeled_seq(context, &op.elements, { - quote!{ ::peg::RuleResult::Matched(__pos, #action) } - }) - ); + _ => { + // atom + pre_rules.push(labeled_seq(context, &op.elements, { + quote! { ::peg::RuleResult::Matched(__pos, #action) } + })); } }; } if !post_rules.is_empty() { - level_code.push(quote!{ + level_code.push(quote! { if #prec >= __min_prec { #( if let ::peg::RuleResult::Matched(__pos, ()) = #post_rules { @@ -705,8 +773,10 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { } let (enter, leave) = if cfg!(feature = "trace") { - (quote!{println!("[PEG_TRACE] Entering level {}", min_prec);}, - quote!{println!("[PEG_TRACE] Leaving level {}", min_prec);}) + ( + quote! {println!("[PEG_TRACE] Entering level {}", min_prec);}, + quote! {println!("[PEG_TRACE] Leaving level {}", min_prec);}, + ) } else { (quote!(), quote!()) }; @@ -714,7 +784,7 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { // The closures below must be defined within the function call to which they are passed // due to https://github.com/rust-lang/rust/issues/41078 - quote!{{ + quote! {{ fn __infix_parse( state: &mut S, err_state: &mut ::peg::error::ErrorState, @@ -760,7 +830,7 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { } } - __infix_parse(__state, __err_state, 0, __pos, + __infix_parse(__state, __err_state, 0, __pos, &|__pos, __state, __err_state, __recurse| { let __lpos = __pos; #( @@ -783,4 +853,3 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream { } } } - diff --git a/peg-runtime/error.rs b/peg-runtime/error.rs index b23dfd0..f2238b7 100644 --- a/peg-runtime/error.rs +++ b/peg-runtime/error.rs @@ -1,8 +1,8 @@ //! Parse error reporting -use std::fmt::{ self, Display, Debug }; -use crate::{ RuleResult, Parse }; +use crate::{Parse, RuleResult}; use std::collections::HashSet; +use std::fmt::{self, Debug, Display}; /// A set of literals or names that failed to match #[derive(PartialEq, Eq, Debug, Clone)] @@ -19,7 +19,7 @@ impl ExpectedSet { impl Display for ExpectedSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if self.expected.is_empty() { + if self.expected.is_empty() { write!(fmt, "")?; } else if self.expected.len() == 1 { write!(fmt, "{}", self.expected.iter().next().unwrap())?; @@ -50,7 +50,11 @@ pub struct ParseError { impl Display for ParseError { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> { - write!(fmt, "error at {}: expected {}", self.location, self.expected) + write!( + fmt, + "error at {}: expected {}", + self.location, self.expected + ) } } @@ -74,7 +78,9 @@ impl ErrorState { max_err_pos: initial_pos, suppress_fail: 0, reparsing_on_error: false, - expected: ExpectedSet { expected: HashSet::new() }, + expected: ExpectedSet { + expected: HashSet::new(), + }, } } @@ -108,4 +114,4 @@ impl ErrorState { expected: self.expected, } } -} \ No newline at end of file +} diff --git a/peg-runtime/lib.rs b/peg-runtime/lib.rs index e1df3af..4cfa72d 100644 --- a/peg-runtime/lib.rs +++ b/peg-runtime/lib.rs @@ -1,11 +1,11 @@ use std::fmt::Display; -pub mod str; -mod slice; pub mod error; +mod slice; +pub mod str; /// The result type used internally in the parser. -/// +/// /// You'll only need this if implementing the `Parse*` traits for a custom input /// type. The public API of a parser adapts errors to `std::result::Result`. #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] @@ -45,4 +45,3 @@ pub trait ParseSlice<'input>: Parse { /// Get a slice of input. fn parse_slice(&'input self, p1: usize, p2: usize) -> Self::Slice; } - diff --git a/peg-runtime/slice.rs b/peg-runtime/slice.rs index f370c21..eb131d1 100644 --- a/peg-runtime/slice.rs +++ b/peg-runtime/slice.rs @@ -1,10 +1,14 @@ -use super::{RuleResult, Parse, ParseElem, ParseLiteral, ParseSlice}; +use super::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult}; impl Parse for [T] { type PositionRepr = usize; - fn start(&self) -> usize { 0 } + fn start(&self) -> usize { + 0 + } - fn position_repr(&self, pos: usize) -> usize { pos } + fn position_repr(&self, pos: usize) -> usize { + pos + } } impl ParseElem for [T] { @@ -13,7 +17,7 @@ impl ParseElem for [T] { fn parse_elem(&self, pos: usize) -> RuleResult { match self[pos..].first() { Some(c) => RuleResult::Matched(pos + 1, c.clone()), - None => RuleResult::Failed + None => RuleResult::Failed, } } } @@ -21,8 +25,8 @@ impl ParseElem for [T] { impl ParseLiteral for [u8] { fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()> { let l = literal.len(); - if self.len() >= pos + l && &self[pos..pos+l] == literal.as_bytes() { - RuleResult::Matched(pos+l, ()) + if self.len() >= pos + l && &self[pos..pos + l] == literal.as_bytes() { + RuleResult::Matched(pos + l, ()) } else { RuleResult::Failed } diff --git a/peg-runtime/str.rs b/peg-runtime/str.rs index 9685ec1..94a4d82 100644 --- a/peg-runtime/str.rs +++ b/peg-runtime/str.rs @@ -1,7 +1,7 @@ //! Utilities for `str` input +use super::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult}; use std::fmt::Display; -use super::{RuleResult, Parse, ParseElem, ParseLiteral, ParseSlice}; /// Line and column within a string #[derive(PartialEq, Eq, Debug, Clone)] @@ -24,13 +24,19 @@ impl Display for LineCol { impl Parse for str { type PositionRepr = LineCol; - fn start(&self) -> usize { 0 } + fn start(&self) -> usize { + 0 + } fn position_repr(&self, pos: usize) -> LineCol { let before = &self[..pos]; - let line = before.as_bytes().iter().filter(|&&c| c == b'\n').count() + 1; - let column = before.chars().rev().take_while(|&c| c != '\n').count() + 1; - LineCol { line, column, offset: pos} + let line = before.as_bytes().iter().filter(|&&c| c == b'\n').count() + 1; + let column = before.chars().rev().take_while(|&c| c != '\n').count() + 1; + LineCol { + line, + column, + offset: pos, + } } } @@ -40,7 +46,7 @@ impl ParseElem for str { fn parse_elem(&self, pos: usize) -> RuleResult { match self[pos..].chars().next() { Some(c) => RuleResult::Matched(pos + c.len_utf8(), c), - None => RuleResult::Failed + None => RuleResult::Failed, } } } @@ -48,8 +54,8 @@ impl ParseElem for str { impl ParseLiteral for str { fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()> { let l = literal.len(); - if self.len() >= pos + l && &self.as_bytes()[pos..pos+l] == literal.as_bytes() { - RuleResult::Matched(pos+l, ()) + if self.len() >= pos + l && &self.as_bytes()[pos..pos + l] == literal.as_bytes() { + RuleResult::Matched(pos + l, ()) } else { RuleResult::Failed } diff --git a/src/lib.rs b/src/lib.rs index 5626fb1..3cf4746 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ //! `rust-peg` is a simple yet flexible parser generator that makes it easy to //! write robust parsers. Based on the [Parsing Expression //! Grammar][wikipedia-peg] formalism, it provides a Rust macro that builds a -//! recursive descent parser from a concise definition of the grammar. +//! recursive descent parser from a concise definition of the grammar. //! //! [wikipedia-peg]: https://en.wikipedia.org/wiki/Parsing_expression_grammar //! @@ -16,7 +16,7 @@ //! Rust code embedded within it //! * Rule-level tracing to debug grammars //! -//! ## Overview +//! ## Overview //! //! The `peg::parser!{}` macro encloses a `grammar NAME() for INPUT_TYPE { ... //! }` definition containing a set of rules which match components of your @@ -40,7 +40,7 @@ //! ## Example //! //! Parse a comma-separated list of numbers surrounded by brackets into a `Vec`: -//! +//! //! ```rust //! peg::parser!{ //! grammar list_parser() for str { @@ -56,11 +56,11 @@ //! assert_eq!(list_parser::list("[1,1,2,3,5,8]"), Ok(vec![1, 1, 2, 3, 5, 8])); //! } //! ``` -//! +//! //! ## Expression Reference //! //! ### Atoms -//! +//! //! * `"keyword"` - _Literal:_ match a literal string. //! * `['0'..='9']` - _Pattern:_ match a single element that matches a Rust `match`-style //! pattern. [(details)](#match-expressions) @@ -72,9 +72,9 @@ //! * `(e)` - _Parentheses:_ wrap an expression into a group to override //! normal precedence. Returns the same value as the inner expression. (Use //! an _Action_ block to set the return value for a sequence). -//! +//! //! ### Combining -//! +//! //! * `e1 e2 e3` - _Sequence:_ match expressions in sequence (`e1` followed by `e2` followed by //! `e3`), ignoring the return values. //! * `a:e1 e2 b:e3 c:e4 { rust }` - _Action:_ match `e1`, `e2`, `e3`, `e4` in @@ -91,7 +91,7 @@ //! parse error with the `&str` `e`. //! * `e1 / e2 / e3` - _Ordered choice:_ try to match `e1`. If the match succeeds, return its //! result, otherwise try `e2`, and so on. -//! +//! //! ### Repetition //! * `expression?` - _Optional:_ match zero or one repetitions of `expression`. Returns an //! `Option`. @@ -103,7 +103,7 @@ //! return the results as a `Vec`. [(details)](#repeat-ranges) //! * `expression ** delim` - _Delimited repeat:_ match zero or more repetitions of `expression` //! delimited with `delim` and return the results as a `Vec`. -//! +//! //! ### Special //! * `$(e)` - _Slice:_ match the expression `e`, and return the slice of the input //! corresponding to the match. @@ -121,7 +121,7 @@ //! [(details)](#precedence-climbing) //! //! ## Expression details -//! +//! //! ### Pattern expressions //! //! The `[pat]` syntax expands into a [Rust `match` @@ -195,9 +195,9 @@ //! As a more complex example, the body of the `peg::parser!{}` macro itself is //! parsed with `peg`, using a [definition of these traits][gh-flat-token-tree] //! for a type that wraps Rust's `TokenTree`. -//! +//! //! [gh-flat-token-tree]: https://github.com/kevinmehall/rust-peg/blob/master/peg-macros/tokens.rs -//! +//! //! ## Error reporting //! //! When a match fails, position information is automatically recorded to report a set of @@ -257,26 +257,26 @@ //! in any other Rust code. //! //! ## Caching -//! +//! //! A `rule` without parameters can be prefixed with `#[cache]` if it is likely //! to be checked repeatedly in the same position. This memoizes the rule result //! as a function of input position, in the style of a [packrat //! parser][wp-peg-packrat]. -//! +//! //! [wp-peg-packrat]: https://en.wikipedia.org/wiki/Parsing_expression_grammar#Implementing_parsers_from_parsing_expression_grammars -//! +//! //! However, idiomatic code avoids structures that parse the same input //! repeatedly, so the use of `#[cache]` is often not a performance win. Simple //! rules may also be faster to re-match than the additional cost of the hash //! table lookup and insert. -//! +//! //! For example, a complex rule called `expr` might benefit from caching if used //! like `expr "x" / expr "y" / expr "z"`, but this could be rewritten to //! `expr ("x" / "y" / "z")` which would be even faster. -//! +//! //! The `precedence!{}` syntax is another way to avoid repeatedly matching //! an expression rule. -//! +//! //! ## Tracing //! //! If you pass the `peg/trace` feature to Cargo when building your project, a diff --git a/tests/trybuild.rs b/tests/trybuild.rs index 61b6949..0ee62a0 100644 --- a/tests/trybuild.rs +++ b/tests/trybuild.rs @@ -5,7 +5,9 @@ fn main() { let rust_ver = option_env!("TRAVIS_RUST_VERSION"); if rust_ver.is_none() { - println!("Note: compile-fail tests are normally only tested on the stable rust compiler in CI."); + println!( + "Note: compile-fail tests are normally only tested on the stable rust compiler in CI." + ); } if rust_ver.is_none() || rust_ver == Some("stable") { @@ -13,6 +15,6 @@ fn main() { } else { println!("Skipping compile-fail tests."); } - + t.pass("tests/run-pass/*.rs"); }