1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use proc_macro2::{Delimiter, TokenStream};
use quote::quote;
use crate::{
ast::{
capture::Quantity,
keyword::{Keyword, KeywordMap},
node::{Pattern, PatternKind},
},
codegen::{logic::Compiler, output::generate_output},
transform::lookahead::inject_lookahead,
};
impl Compiler {
fn compile_edge_peek(&self, keyword: &Keyword) -> TokenStream {
match keyword {
Keyword::Custom {
punctuation: true,
content,
..
} => {
let parse_punct = content.chars().map(|ch| {
let punct = Keyword::Rust(ch.to_string());
quote! {
_edge_fork.parse::<#punct>()?;
}
});
quote! {
{
let _edge_fork = input.fork();
(|| -> ::syn::Result<()> {
#(#parse_punct)*
::std::result::Result::Ok(())
})().is_ok()
}
}
}
_ => quote! {
input.peek(#keyword)
},
}
}
pub fn compile_pattern(&mut self, pattern: &Pattern) -> TokenStream {
let mut tokens = TokenStream::new();
let mut keyword_map = KeywordMap::new();
// 1. 创建一个临时的 Buffer 来存放主体逻辑代码
let mut body_stream = TokenStream::new();
match &pattern.kind {
PatternKind::Literal(keyword) => {
keyword.define(&mut keyword_map);
// 2. 使用 extend 追加到 body_stream,而不是替换
body_stream.extend(quote! {
input.parse::<#keyword>()?;
});
}
PatternKind::Group {
delimiter,
children,
} => {
let children = inject_lookahead(children.clone());
let mac: proc_macro2::TokenStream = match delimiter {
Delimiter::Brace => quote! { ::syn::braced! },
Delimiter::Bracket => quote! { ::syn::bracketed! },
Delimiter::Parenthesis => quote! { ::syn::parenthesized! },
Delimiter::None => quote! {},
};
let mut pattern_token = TokenStream::new();
pattern_token.extend(children.iter().map(|pattern| self.compile_pattern(pattern)));
if matches!(delimiter, Delimiter::None) {
tokens.extend(pattern_token);
return tokens;
}
let captures = pattern.collect_captures();
let (capture_init, struct_def, struct_expr, ..) =
generate_output(&captures, None, None);
// 追加到 body_stream
body_stream.extend(quote! {
{
#struct_def
let _input;
let _ = #mac(_input in input);
let parser = |input: ::syn::parse::ParseStream| -> ::syn::Result<Output> {
#capture_init
#pattern_token
::std::result::Result::Ok(#struct_expr)
};
#struct_expr = parser(&_input)?;
}
});
}
PatternKind::Capture(capture) => {
let captures = capture.collect_captures();
let (capture_init, struct_def, struct_expr, ..) =
generate_output(&captures, None, None);
let cap_tokens = self.compile_capture(capture);
match &capture.edge {
Some(keyword) if !matches!(capture.quantity, Quantity::Optional) => {
let edge_peek = self.compile_edge_peek(keyword);
// 3. Lookahead 逻辑,现在追加到 body_stream
body_stream.extend(quote! {
{
let mut _input_tokens = ::std::vec::Vec::<::proc_macro2::TokenTree>::new();
while !(#edge_peek) {
_input_tokens.push(input.parse::<::proc_macro2::TokenTree>()?);
}
if let ::std::option::Option::Some(::proc_macro2::TokenTree::Punct(_punct)) =
_input_tokens.last_mut()
{
if _punct.spacing() == ::proc_macro2::Spacing::Joint {
let mut _alone = ::proc_macro2::Punct::new(
_punct.as_char(),
::proc_macro2::Spacing::Alone,
);
_alone.set_span(_punct.span());
*_punct = _alone;
}
}
let _input = _input_tokens
.into_iter()
.collect::<::proc_macro2::TokenStream>();
#struct_def
let parser = |input: ::syn::parse::ParseStream| -> ::syn::Result<Output> {
#capture_init
{
#cap_tokens
}
::std::result::Result::Ok(#struct_expr)
};
// 这里解析刚才吃进去的流
#struct_expr = ::syn::parse::Parser::parse2(parser, _input)?;
}
});
}
Some(_) | None => {
body_stream.extend(quote! {
{
#cap_tokens
}
});
}
};
}
}
let keyword_map_tokens = self.compile_keyword_map(keyword_map);
// 4. 最后一次性把所有东西包装起来塞给 tokens
tokens.extend(quote! {
#keyword_map_tokens
#body_stream
});
tokens
}
}