Skip to content

Commit 3641e71

Browse files
committed
Change CTParserBuilder src gen to use the quote crate.
1 parent d70b294 commit 3641e71

File tree

4 files changed

+98
-27
lines changed

4 files changed

+98
-27
lines changed

cfgrammar/src/lib/yacc/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub use self::{
1010
grammar::{AssocKind, Precedence, SentenceGenerator, YaccGrammar},
1111
parser::{YaccGrammarError, YaccGrammarErrorKind, YaccGrammarWarning, YaccGrammarWarningKind},
1212
};
13+
use proc_macro2::TokenStream;
14+
use quote::quote;
1315

1416
#[cfg(feature = "serde")]
1517
use serde::{Deserialize, Serialize};
@@ -39,6 +41,18 @@ pub enum YaccKind {
3941
Eco,
4042
}
4143

44+
impl quote::ToTokens for YaccKind {
45+
fn to_tokens(&self, tokens: &mut TokenStream) {
46+
tokens.extend(match *self {
47+
YaccKind::Grmtools => quote!(::cfgrammar::yacc::YaccKind::Grmtools),
48+
YaccKind::Original(action_kind) => {
49+
quote!(::cfgrammar::yacc::YaccKind::Original(#action_kind))
50+
}
51+
YaccKind::Eco => quote!(::cfgrammar::yacc::YaccKind::Eco),
52+
})
53+
}
54+
}
55+
4256
#[derive(Clone, Copy, Debug)]
4357
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4458
pub enum YaccOriginalActionKind {
@@ -50,3 +64,19 @@ pub enum YaccOriginalActionKind {
5064
/// Do not do execute actions of any sort.
5165
NoAction,
5266
}
67+
68+
impl quote::ToTokens for YaccOriginalActionKind {
69+
fn to_tokens(&self, tokens: &mut TokenStream) {
70+
tokens.extend(match *self {
71+
YaccOriginalActionKind::UserAction => {
72+
quote!(::cfgrammar::yacc::YaccOriginalActionKind::UserAction)
73+
}
74+
YaccOriginalActionKind::GenericParseTree => {
75+
quote!(::cfgrammar::yacc::YaccOriginalActionKind::GenericParseTree)
76+
}
77+
YaccOriginalActionKind::NoAction => {
78+
quote!(::cfgrammar::yacc::YaccOriginalActionKind::NoAction)
79+
}
80+
})
81+
}
82+
}

lrpar/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ indexmap.workspace = true
3434
lazy_static.workspace = true
3535
num-traits.workspace = true
3636
packedvec.workspace = true
37+
proc-macro2.workspace = true
38+
quote.workspace = true
39+
regex.workspace = true
3740
serde = { workspace = true, features = ["derive"] }
3841
static_assertions.workspace = true
3942
vob.workspace = true
40-
regex.workspace = true
4143

4244
[dev-dependencies]
4345
tempfile = "3.0"

lrpar/src/lib/ctbuilder.rs

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ use filetime::FileTime;
2727
use lazy_static::lazy_static;
2828
use lrtable::{from_yacc, statetable::Conflicts, Minimiser, StateGraph, StateTable};
2929
use num_traits::{AsPrimitive, PrimInt, Unsigned};
30+
use proc_macro2::{Literal, TokenStream};
31+
use quote::{quote, ToTokens, TokenStreamExt};
3032
use regex::Regex;
3133
use serde::{de::DeserializeOwned, Serialize};
3234

@@ -52,6 +54,34 @@ struct CTConflictsError<StorageT: Eq + Hash> {
5254
stable: StateTable<StorageT>,
5355
}
5456

57+
/// The quote impl of `ToTokens` for `Option` prints an empty string for `None`
58+
/// and the inner value for `Some(inner_value)`.
59+
///
60+
/// This wrapper instead emits both `Some` and `None` variants.
61+
/// See: [quote #20](https://github.com/dtolnay/quote/issues/20)
62+
struct QuoteOption<T>(Option<T>);
63+
64+
impl<T: ToTokens> ToTokens for QuoteOption<T> {
65+
fn to_tokens(&self, tokens: &mut TokenStream) {
66+
tokens.append_all(match self.0 {
67+
Some(ref t) => quote! { ::std::option::Option::Some(#t) },
68+
None => quote! { ::std::option::Option::None },
69+
});
70+
}
71+
}
72+
73+
/// The quote impl of `ToTokens` for `usize` prints literal values
74+
/// including a type suffix for example `0usize`.
75+
///
76+
/// This wrapper omits the type suffix emitting `0` instead.
77+
struct UnsuffixedUsize(usize);
78+
79+
impl ToTokens for UnsuffixedUsize {
80+
fn to_tokens(&self, tokens: &mut TokenStream) {
81+
tokens.append(Literal::usize_unsuffixed(self.0))
82+
}
83+
}
84+
5585
impl<StorageT> fmt::Display for CTConflictsError<StorageT>
5686
where
5787
StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
@@ -733,17 +763,23 @@ where
733763
// Record the time that this version of lrpar was built. If the source code changes and
734764
// rustc forces a recompile, this will change this value, causing anything which depends on
735765
// this build of lrpar to be recompiled too.
736-
writeln!(cache, " Build time: {:?}", env!("VERGEN_BUILD_TIMESTAMP")).ok();
737-
738-
writeln!(cache, " Grammar path: {:?}", self.grammar_path).ok();
739-
writeln!(cache, " Mod name: {:?}", self.mod_name).ok();
740-
writeln!(cache, " Recoverer: {:?}", self.recoverer).ok();
741-
writeln!(cache, " YaccKind: {:?}", self.yacckind).ok();
742-
writeln!(cache, " Visibility: {:?}", self.visibility.cow_str()).ok();
766+
let build_time = env!("VERGEN_BUILD_TIMESTAMP");
767+
let grammar_path = self.grammar_path.as_ref().unwrap().to_string_lossy();
768+
let mod_name = self.mod_name;
769+
let recoverer = self.recoverer;
770+
let yacckind = self.yacckind;
771+
let visibility = self.visibility.cow_str();
772+
let error_on_conflicts = self.error_on_conflicts;
773+
writeln!(cache, " Build time: {}", quote!(#build_time)).ok();
774+
writeln!(cache, " Grammar path: {}", quote!(#grammar_path)).ok();
775+
writeln!(cache, " Mod name: {}", quote!(#mod_name)).ok();
776+
writeln!(cache, " Recoverer: {}", quote!(#recoverer)).ok();
777+
writeln!(cache, " YaccKind: {}", quote!(#yacckind)).ok();
778+
writeln!(cache, " Visibility: {}", quote!(#visibility)).ok();
743779
writeln!(
744780
cache,
745-
" Error on conflicts: {:?}\n",
746-
self.error_on_conflicts
781+
" Error on conflicts: {}\n",
782+
quote!(#error_on_conflicts)
747783
)
748784
.ok();
749785

@@ -840,11 +876,8 @@ where
840876
let wrappers = grm
841877
.iter_pidxs()
842878
.map(|pidx| {
843-
format!(
844-
"&{prefix}wrapper_{}",
845-
usize::from(pidx),
846-
prefix = ACTION_PREFIX
847-
)
879+
let pidx = UnsuffixedUsize(usize::from(pidx));
880+
format!("&{prefix}wrapper_{}", quote!(#pidx), prefix = ACTION_PREFIX)
848881
})
849882
.collect::<Vec<_>>()
850883
.join(",\n ");
@@ -867,6 +900,7 @@ where
867900
wrappers = wrappers,
868901
edition_lifetime = if self.rust_edition != RustEdition::Rust2015 { "'_, " } else { "" },
869902
).ok();
903+
let ridx = UnsuffixedUsize(usize::from(self.user_start_ridx(grm)));
870904
write!(
871905
outs,
872906
"
@@ -880,7 +914,7 @@ where
880914
parse_param = parse_param,
881915
actionskind = ACTIONS_KIND,
882916
actionskindprefix = ACTIONS_KIND_PREFIX,
883-
ridx = usize::from(self.user_start_ridx(grm)),
917+
ridx = quote!(#ridx),
884918
recoverer = recoverer,
885919
)
886920
.ok();
@@ -920,7 +954,7 @@ where
920954
if !grm.rule_to_prods(ridx).contains(&grm.start_prod()) {
921955
write!(
922956
outs,
923-
" #[allow(dead_code)]\n pub const R_{}: {} = {:?};\n",
957+
" #[allow(dead_code)]\n pub const R_{}: {} = {};\n",
924958
grm.rule_name_str(ridx).to_ascii_uppercase(),
925959
type_name::<StorageT>(),
926960
usize::from(ridx)
@@ -934,10 +968,8 @@ where
934968
fn gen_token_epp(&self, grm: &YaccGrammar<StorageT>) -> String {
935969
let mut tidxs = Vec::new();
936970
for tidx in grm.iter_tidxs() {
937-
match grm.token_epp(tidx) {
938-
Some(n) => tidxs.push(format!("Some(\"{}\")", str_escape(n))),
939-
None => tidxs.push("None".to_string()),
940-
}
971+
let tok_epp = QuoteOption(grm.token_epp(tidx));
972+
tidxs.push(format!("{}", quote!(#tok_epp)));
941973
}
942974
format!(
943975
" const {prefix}EPP: &[::std::option::Option<&str>] = &[{}];
@@ -966,6 +998,7 @@ where
966998
};
967999
for pidx in grm.iter_pidxs() {
9681000
let ridx = grm.prod_to_rule(pidx);
1001+
let pidx_num = UnsuffixedUsize(usize::from(pidx));
9691002

9701003
// Iterate over all $-arguments and replace them with their respective
9711004
// element from the argument vector (e.g. $1 is replaced by args[0]). At
@@ -977,7 +1010,7 @@ where
9771010
mut {prefix}args: ::std::vec::Drain<{edition_lifetime} ::lrpar::parser::AStackType<<{lexertypest} as ::lrpar::LexerTypes>::LexemeT, {actionskind}<'input>>>,
9781011
{parse_paramdef})
9791012
-> {actionskind}<'input> {{",
980-
usize::from(pidx),
1013+
quote!(#pidx_num),
9811014
storaget = type_name::<StorageT>(),
9821015
lexertypest = type_name::<LexerTypesT>(),
9831016
prefix = ACTION_PREFIX,
@@ -1242,11 +1275,6 @@ where
12421275
}
12431276
}
12441277

1245-
/// Return a version of the string `s` which is safe to embed in source code as a string.
1246-
fn str_escape(s: &str) -> String {
1247-
s.replace('\\', "\\\\").replace('"', "\\\"")
1248-
}
1249-
12501278
/// This function is called by generated files; it exists so that generated files don't require a
12511279
/// dependency on serde and rmps.
12521280
#[doc(hidden)]

lrpar/src/lib/parser.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use cactus::Cactus;
1212
use cfgrammar::{yacc::YaccGrammar, RIdx, Span, TIdx};
1313
use lrtable::{Action, StIdx, StateTable};
1414
use num_traits::{AsPrimitive, PrimInt, Unsigned};
15+
use proc_macro2::TokenStream;
16+
use quote::quote;
1517
#[cfg(feature = "serde")]
1618
use serde::{Deserialize, Serialize};
1719

@@ -621,6 +623,15 @@ pub enum RecoveryKind {
621623
None,
622624
}
623625

626+
impl quote::ToTokens for RecoveryKind {
627+
fn to_tokens(&self, tokens: &mut TokenStream) {
628+
tokens.extend(match *self {
629+
RecoveryKind::CPCTPlus => quote!(::lrpar::RecoveryKind::CPCTPlus),
630+
RecoveryKind::None => quote!(::lrpar::RecoveryKind::None),
631+
})
632+
}
633+
}
634+
624635
/// A lexing or parsing error. Although the two are quite distinct in terms of what can be reported
625636
/// to users, both can (at least conceptually) occur at any point of the intertwined lexing/parsing
626637
/// process.

0 commit comments

Comments
 (0)