Skip to content

Commit 5135a01

Browse files
authored
Merge pull request #494 from ratmice/lrlex_323
Remove debug formatting for CTLexerBuilder src gen
2 parents 2d554c2 + 3641e71 commit 5135a01

File tree

10 files changed

+218
-76
lines changed

10 files changed

+218
-76
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ sparsevec = "0.2"
4444
static_assertions = "1.1"
4545
unicode-width = "0.1.11"
4646
vob = ">=3.0.2"
47+
proc-macro2 = "1.0"

cfgrammar/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ num-traits.workspace = true
2121
regex.workspace = true
2222
serde = { workspace = true, features = ["derive"], optional = true }
2323
vob = { workspace = true, features = ["serde"] }
24+
quote.workspace = true
25+
proc-macro2.workspace = true

cfgrammar/src/lib/span.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use proc_macro2::TokenStream;
2+
use quote::{quote, ToTokens, TokenStreamExt};
13
#[cfg(feature = "serde")]
24
use serde::{Deserialize, Serialize};
35

@@ -54,3 +56,10 @@ pub trait Spanned: std::fmt::Display {
5456
/// Returns the `SpansKind` associated with this error.
5557
fn spanskind(&self) -> crate::yacc::parser::SpansKind;
5658
}
59+
60+
impl ToTokens for Span {
61+
fn to_tokens(&self, tokens: &mut TokenStream) {
62+
let Span { start, end } = self;
63+
tokens.append_all(quote! {::cfgrammar::Span::new(#start, #end)});
64+
}
65+
}

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+
}

lrlex/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@ lazy_static.workspace = true
3333
regex.workspace = true
3434
regex-syntax.workspace = true
3535
num-traits.workspace = true
36+
proc-macro2.workspace = true
3637
quote.workspace = true
3738
serde.workspace = true

lrlex/src/lib/ctbuilder.rs

Lines changed: 95 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ use cfgrammar::{newlinecache::NewlineCache, Spanned};
1919
use lazy_static::lazy_static;
2020
use lrpar::{CTParserBuilder, LexerTypes};
2121
use num_traits::{AsPrimitive, PrimInt, Unsigned};
22-
use quote::quote;
22+
use proc_macro2::TokenStream;
23+
use quote::{quote, ToTokens, TokenStreamExt};
2324
use regex::Regex;
2425
use serde::Serialize;
2526

@@ -78,11 +79,48 @@ pub enum RustEdition {
7879
Rust2021,
7980
}
8081

82+
/// The quote impl of `ToTokens` for `Option` prints an empty string for `None`
83+
/// and the inner value for `Some(inner_value)`.
84+
///
85+
/// This wrapper instead emits both `Some` and `None` variants.
86+
/// See: [quote #20](https://github.com/dtolnay/quote/issues/20)
87+
struct QuoteOption<T>(Option<T>);
88+
89+
impl<T: ToTokens> ToTokens for QuoteOption<T> {
90+
fn to_tokens(&self, tokens: &mut TokenStream) {
91+
tokens.append_all(match self.0 {
92+
Some(ref t) => quote! { ::std::option::Option::Some(#t) },
93+
None => quote! { ::std::option::Option::None },
94+
});
95+
}
96+
}
97+
98+
/// This wrapper adds a missing impl of `ToTokens` for tuples.
99+
/// For a tuple `(a, b)` emits `(a.to_tokens(), b.to_tokens())`
100+
struct QuoteTuple<T>(T);
101+
102+
impl<A: ToTokens, B: ToTokens> ToTokens for QuoteTuple<(A, B)> {
103+
fn to_tokens(&self, tokens: &mut TokenStream) {
104+
let (a, b) = &self.0;
105+
tokens.append_all(quote!((#a, #b)));
106+
}
107+
}
108+
109+
/// The wrapped `&str` value will be emitted with a call to `to_string()`
110+
struct QuoteToString<'a>(&'a str);
111+
112+
impl ToTokens for QuoteToString<'_> {
113+
fn to_tokens(&self, tokens: &mut TokenStream) {
114+
let x = &self.0;
115+
tokens.append_all(quote! { #x.to_string() });
116+
}
117+
}
118+
81119
/// A `CTLexerBuilder` allows one to specify the criteria for building a statically generated
82120
/// lexer.
83121
pub struct CTLexerBuilder<'a, LexerTypesT: LexerTypes = DefaultLexerTypes<u32>>
84122
where
85-
LexerTypesT::StorageT: Debug + Eq + Hash,
123+
LexerTypesT::StorageT: Debug + Eq + Hash + ToTokens,
86124
usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
87125
{
88126
lrpar_config: Option<Box<dyn Fn(CTParserBuilder<LexerTypesT>) -> CTParserBuilder<LexerTypesT>>>,
@@ -108,7 +146,7 @@ impl CTLexerBuilder<'_, DefaultLexerTypes<u32>> {
108146
impl<'a, LexerTypesT: LexerTypes> CTLexerBuilder<'a, LexerTypesT>
109147
where
110148
LexerTypesT::StorageT:
111-
'static + Debug + Eq + Hash + PrimInt + Serialize + TryFrom<usize> + Unsigned,
149+
'static + Debug + Eq + Hash + PrimInt + Serialize + TryFrom<usize> + Unsigned + ToTokens,
112150
usize: AsPrimitive<LexerTypesT::StorageT>,
113151
{
114152
/// Create a new [CTLexerBuilder].
@@ -438,31 +476,52 @@ pub fn lexerdef() -> {lexerdef_type} {{
438476
)
439477
.ok();
440478

479+
let RegexOptions {
480+
dot_matches_new_line,
481+
multi_line,
482+
octal,
483+
posix_escapes,
484+
case_insensitive,
485+
unicode,
486+
swap_greed,
487+
ignore_whitespace,
488+
size_limit,
489+
dfa_size_limit,
490+
nest_limit,
491+
} = self.regex_options;
492+
let case_insensitive = QuoteOption(case_insensitive);
493+
let unicode = QuoteOption(unicode);
494+
let swap_greed = QuoteOption(swap_greed);
495+
let ignore_whitespace = QuoteOption(ignore_whitespace);
496+
let size_limit = QuoteOption(size_limit);
497+
let dfa_size_limit = QuoteOption(dfa_size_limit);
498+
let nest_limit = QuoteOption(nest_limit);
499+
441500
outs.push_str(&format!(
442501
"let regex_options = ::lrlex::RegexOptions {{
443-
dot_matches_new_line: {dot_matches_new_line:?},
444-
multi_line: {multi_line:?},
445-
octal: {octal:?},
446-
posix_escapes: {posix_escapes:?},
447-
case_insensitive: {case_insensitive:?},
448-
unicode: {unicode:?},
449-
swap_greed: {swap_greed:?},
450-
ignore_whitespace: {ignore_whitespace:?},
451-
size_limit: {size_limit:?},
452-
dfa_size_limit: {dfa_size_limit:?},
453-
nest_limit: {nest_limit:?},
502+
dot_matches_new_line: {dot_matches_new_line},
503+
multi_line: {multi_line},
504+
octal: {octal},
505+
posix_escapes: {posix_escapes},
506+
case_insensitive: {case_insensitive},
507+
unicode: {unicode},
508+
swap_greed: {swap_greed},
509+
ignore_whitespace: {ignore_whitespace},
510+
size_limit: {size_limit},
511+
dfa_size_limit: {dfa_size_limit},
512+
nest_limit: {nest_limit},
454513
}};",
455-
dot_matches_new_line = self.regex_options.dot_matches_new_line,
456-
multi_line = self.regex_options.multi_line,
457-
octal = self.regex_options.octal,
458-
posix_escapes = self.regex_options.posix_escapes,
459-
case_insensitive = self.regex_options.case_insensitive,
460-
unicode = self.regex_options.unicode,
461-
swap_greed = self.regex_options.swap_greed,
462-
ignore_whitespace = self.regex_options.ignore_whitespace,
463-
size_limit = self.regex_options.size_limit,
464-
dfa_size_limit = self.regex_options.dfa_size_limit,
465-
nest_limit = self.regex_options.nest_limit,
514+
dot_matches_new_line = quote!(#dot_matches_new_line),
515+
multi_line = quote!(#multi_line),
516+
octal = quote!(#octal),
517+
posix_escapes = quote!(#posix_escapes),
518+
case_insensitive = quote!(#case_insensitive),
519+
unicode = quote!(#unicode),
520+
swap_greed = quote!(#swap_greed),
521+
ignore_whitespace = quote!(#ignore_whitespace),
522+
size_limit = quote!(#size_limit),
523+
dfa_size_limit = quote!(#dfa_size_limit),
524+
nest_limit = quote!(#nest_limit),
466525
));
467526

468527
outs.push_str(" let start_states: Vec<StartState> = vec![");
@@ -485,35 +544,22 @@ pub fn lexerdef() -> {lexerdef_type} {{
485544

486545
// Individual rules
487546
for r in lexerdef.iter_rules() {
488-
let tok_id = match r.tok_id {
489-
Some(ref t) => format!("Some({:?})", t),
490-
None => "None".to_owned(),
491-
};
492-
let n = match r.name() {
493-
Some(ref n) => format!("Some({}.to_string())", quote!(#n)),
494-
None => "None".to_owned(),
495-
};
496-
let target_state = match &r.target_state() {
497-
Some((id, op)) => format!("Some(({}, ::lrlex::StartStateOperation::{:?}))", id, op),
498-
None => "None".to_owned(),
499-
};
500-
let n_span = format!(
501-
"::cfgrammar::Span::new({}, {})",
502-
r.name_span().start(),
503-
r.name_span().end()
504-
);
505-
let regex = &r.re_str;
547+
let tok_id = QuoteOption(r.tok_id);
548+
let n = QuoteOption(r.name().map(QuoteToString));
549+
let target_state = QuoteOption(r.target_state().map(|(x, y)| QuoteTuple((x, y))));
550+
let n_span = r.name_span();
551+
let regex = QuoteToString(&r.re_str);
506552
let start_states = r.start_states();
507553
write!(
508554
outs,
509555
"
510556
Rule::new(::lrlex::unstable_api::InternalPublicApi, {}, {}, {}, {}.to_string(), {}.to_vec(), {}, &regex_options).unwrap(),",
511-
tok_id,
512-
n,
513-
n_span,
557+
quote!(#tok_id),
558+
quote!(#n),
559+
quote!(#n_span),
514560
quote!(#regex),
515561
quote!([#(#start_states),*]),
516-
target_state,
562+
quote!(#target_state),
517563
)
518564
.ok();
519565
}
@@ -537,10 +583,10 @@ pub fn lexerdef() -> {lexerdef_type} {{
537583
if RE_TOKEN_ID.is_match(n) {
538584
write!(
539585
outs,
540-
"#[allow(dead_code)]\npub const T_{}: {} = {:?};\n",
586+
"#[allow(dead_code)]\npub const T_{}: {} = {};\n",
541587
n.to_ascii_uppercase(),
542588
type_name::<LexerTypesT::StorageT>(),
543-
*id
589+
quote!(#id)
544590
)
545591
.ok();
546592
}

lrlex/src/lib/parser.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ pub enum StartStateOperation {
7676
Pop,
7777
}
7878

79+
use proc_macro2::TokenStream;
80+
use quote::quote;
81+
impl quote::ToTokens for StartStateOperation {
82+
fn to_tokens(&self, tokens: &mut TokenStream) {
83+
tokens.extend(match *self {
84+
StartStateOperation::ReplaceStack => quote!(::lrlex::StartStateOperation::ReplaceStack),
85+
StartStateOperation::Push => quote!(::lrlex::StartStateOperation::Push),
86+
StartStateOperation::Pop => quote!(::lrlex::StartStateOperation::Pop),
87+
})
88+
}
89+
}
90+
7991
pub(super) struct LexParser<LexerTypesT: LexerTypes>
8092
where
8193
usize: AsPrimitive<LexerTypesT::StorageT>,

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"

0 commit comments

Comments
 (0)