Skip to content

Commit 6385ed5

Browse files
committed
Make proc_macro work on stable
Use Span debug information to get source text, fixed #13
1 parent 1675fe1 commit 6385ed5

File tree

1 file changed

+71
-96
lines changed

1 file changed

+71
-96
lines changed

crates/proc_macros/src/lib.rs

Lines changed: 71 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
1-
#![feature(proc_macro_span)]
2-
3-
extern crate proc_macro;
4-
use std::iter::Peekable;
51
use proc_macro2::{
6-
token_stream::IntoIter,
72
TokenStream,
83
TokenTree,
9-
LineColumn,
104
Ident,
115
Literal,
6+
Span,
127
};
138
use quote::quote;
149

1510
#[proc_macro]
1611
pub fn run_cmd(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
17-
let mut s = Source::new();
18-
let (vars, lits, src) = s.reconstruct_from(TokenStream::from(input));
12+
let (vars, lits, src) = source_text(input);
1913
quote! (
2014
cmd_lib_core::run_cmd_with_ctx(
2115
#src,
@@ -31,8 +25,7 @@ pub fn run_cmd(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
3125

3226
#[proc_macro]
3327
pub fn run_fun(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
34-
let mut s = Source::new();
35-
let (vars, lits, src) = s.reconstruct_from(TokenStream::from(input));
28+
let (vars, lits, src) = source_text(input);
3629
quote! (
3730
cmd_lib_core::run_fun_with_ctx(
3831
#src,
@@ -46,105 +39,87 @@ pub fn run_fun(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
4639
).into()
4740
}
4841

49-
// from inline-python: https://blog.m-ou.se/writing-python-inside-rust-1/
50-
struct Source {
51-
source: String,
52-
line: usize,
53-
col: usize,
54-
sym_table_vars: Vec<Ident>,
55-
str_lits: Vec<Literal>,
56-
}
57-
58-
impl Source {
59-
fn new() -> Self {
60-
Self {
61-
source: String::new(),
62-
sym_table_vars: vec![],
63-
str_lits: vec![],
64-
line: 1,
65-
col: 0,
42+
fn span_location(span: &Span) -> (usize, usize) {
43+
let s = format!("{:?}", span);
44+
let mut start = 0;
45+
let mut end = 0;
46+
let mut parse_second = false;
47+
for c in s.chars().skip(6) {
48+
if c == '.' {
49+
parse_second = true;
50+
} else if c.is_ascii_digit() {
51+
let digit = c.to_digit(10).unwrap() as usize;
52+
if !parse_second {
53+
start = start * 10 + digit;
54+
} else {
55+
end = end * 10 + digit;
56+
}
6657
}
6758
}
59+
(start, end)
60+
}
6861

69-
fn reconstruct_from(&mut self, input: TokenStream) -> (&Vec<Ident>, &Vec<Literal>, &str) {
70-
let mut input = input.into_iter().peekable();
71-
let mut with_captures = false;
72-
73-
if let Some(t) = input.peek() {
74-
if let TokenTree::Punct(ch) = &t {
75-
if ch.as_char() == '|' {
76-
with_captures = true;
77-
}
78-
}
79-
}
62+
fn source_text(input: proc_macro::TokenStream) -> (Vec<Ident>, Vec<Literal>, String) {
63+
let input = TokenStream::from(input);
64+
let mut source_text = String::new();
65+
let mut sym_table_vars: Vec<Ident> = vec![];
66+
let mut str_lits: Vec<Literal> = vec![];
67+
let mut end = 0;
68+
let mut with_captures = false;
69+
let mut expect_var = false;
70+
for t in input {
71+
let (_start, _end) = span_location(&t.span());
72+
let src = t.to_string();
8073
if with_captures {
81-
self.parse_captures(&mut input);
82-
}
83-
84-
while let Some(t) = input.next() {
85-
if let TokenTree::Group(g) = t {
86-
let s = g.to_string();
87-
self.add_whitespace(g.span_open().start());
88-
self.add_str(&s[..1]); // the '[', '{', or '('.
89-
self.reconstruct_from(g.stream());
90-
self.add_whitespace(g.span_close().start());
91-
self.add_str(&s[s.len() - 1..]); // the ']', '}', or ')'.
74+
if expect_var {
75+
if let TokenTree::Ident(var) = t {
76+
sym_table_vars.push(var);
77+
}
9278
} else {
93-
self.add_whitespace(t.span().start());
94-
if let TokenTree::Literal(lit) = t {
95-
let s = lit.to_string();
96-
if s.starts_with("\"") || s.starts_with("r") {
97-
self.str_lits.push(lit);
98-
}
99-
self.add_str(&s);
100-
} else if let TokenTree::Ident(var) = t {
101-
if self.source.ends_with("$") || self.source.ends_with("${") {
102-
self.add_str(&var.to_string());
103-
self.sym_table_vars.push(var);
79+
if let TokenTree::Punct(ch) = t {
80+
if ch.as_char() == '|' {
81+
with_captures = false;
10482
} else {
105-
self.add_str(&var.to_string());
83+
assert_eq!(ch.as_char(), ',');
10684
}
107-
} else {
108-
self.add_str(&t.to_string());
10985
}
11086
}
111-
}
112-
(&self.sym_table_vars, &self.str_lits, &self.source)
113-
}
114-
115-
fn parse_captures(&mut self, input: &mut Peekable<IntoIter>) {
116-
input.next();
117-
while let Some(TokenTree::Ident(var)) = input.next() {
118-
self.sym_table_vars.push(var);
119-
if let Some(TokenTree::Punct(ch)) = input.next() {
120-
if ch.as_char() == ',' {
87+
expect_var = !expect_var;
88+
} else if source_text.ends_with("$") {
89+
if let TokenTree::Group(g) = t {
90+
for tt in g.stream() {
91+
if let TokenTree::Ident(var) = tt {
92+
source_text += "{";
93+
source_text += &var.to_string();
94+
source_text += "}";
95+
sym_table_vars.push(var);
96+
break;
97+
}
98+
}
99+
} else if let TokenTree::Ident(var) = t {
100+
source_text += &var.to_string();
101+
sym_table_vars.push(var);
102+
}
103+
} else {
104+
if let TokenTree::Punct(ch) = t {
105+
if end == 0 && ch.as_char() == '|' {
106+
with_captures = true;
107+
expect_var = true;
121108
continue;
122-
} else if ch.as_char() == '|' {
123-
break;
124-
} else {
125-
unreachable!();
126109
}
127-
} else {
128-
unreachable!();
110+
} else if let TokenTree::Literal(lit) = t {
111+
let s = lit.to_string();
112+
if s.starts_with("\"") || s.starts_with("r") {
113+
str_lits.push(lit);
114+
}
129115
}
130-
}
131-
}
132116

133-
fn add_str(&mut self, s:&str) {
134-
// let's assume for now s contains no newlines.
135-
self.source += s;
136-
self.col += s.len();
137-
}
138-
139-
fn add_whitespace(&mut self, loc: LineColumn) {
140-
while self.line < loc.line {
141-
self.source.push('\n');
142-
self.line += 1;
143-
self.col = 0;
144-
}
145-
while self.col < loc.column {
146-
self.source.push(' ');
147-
self.col += 1;
117+
if end != 0 && end < _start {
118+
source_text += " ";
119+
}
120+
source_text += &src;
148121
}
122+
end = _end;
149123
}
124+
(sym_table_vars, str_lits, source_text)
150125
}

0 commit comments

Comments
 (0)