Skip to content

Commit ffc5fe3

Browse files
committed
Add GotoCallRewriter
1 parent d8f8407 commit ffc5fe3

3 files changed

Lines changed: 71 additions & 3 deletions

File tree

libcc2rs-macros/src/goto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use proc_macro2::Span;
66
use syn::parse::{Parse, ParseStream};
77
use syn::{Block, Expr, ExprBlock, Lifetime, Stmt, parse_macro_input};
88

9-
use crate::state_machine::{Arm, GotoStateMachine, StateMachineNames, StateMachine};
9+
use crate::state_machine::{Arm, GotoStateMachine, StateMachine, StateMachineNames};
1010

1111
pub fn expand(input: TokenStream) -> TokenStream {
1212
let GotoBlockInput { arms } = parse_macro_input!(input as GotoBlockInput);

libcc2rs-macros/src/state_machine.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,12 @@ impl GotoStateMachine {
107107

108108
impl StateMachine for GotoStateMachine {
109109
fn emit(self) -> TokenStream2 {
110-
let StateMachineNames { label: lbl, state: s, break_flag, cont_flag } = self.names;
110+
let StateMachineNames {
111+
label: lbl,
112+
state: s,
113+
break_flag,
114+
cont_flag,
115+
} = self.names;
111116

112117
let n = self.arms.len();
113118
let mut arms_have_break = false;
@@ -118,6 +123,17 @@ impl StateMachine for GotoStateMachine {
118123
.enumerate()
119124
.map(|(i, arm)| {
120125
let mut body = arm.body.clone();
126+
GotoRewriter {
127+
map: &self
128+
.arms
129+
.iter()
130+
.enumerate()
131+
.map(|(i, a)| (a.label.clone(), i as u32))
132+
.collect(),
133+
state: s.clone(),
134+
sm_label: lbl.clone(),
135+
}
136+
.visit_expr_mut(&mut body);
121137
let (had_br, had_cn) =
122138
Self::propagate_rewrite(&mut body, &lbl, &break_flag, &cont_flag);
123139
arms_have_break |= had_br;
@@ -148,6 +164,58 @@ impl StateMachine for GotoStateMachine {
148164
}
149165
}
150166

167+
// Rewrites `goto!('label)` into `{ __s = <target index>; continue '__sm; }`.
168+
struct GotoRewriter<'a> {
169+
// Map with labels and their indices inside the current state machine. Used to check if the
170+
// label the goto jumps to is part of the current state machine. If it is, emit
171+
// `__s = map[label]`
172+
map: &'a HashMap<String, u32>,
173+
state: Ident,
174+
sm_label: Lifetime,
175+
}
176+
177+
impl GotoRewriter<'_> {
178+
fn expand_goto_into_state_machine_jump(&self, tokens: &TokenStream2) -> Option<Expr> {
179+
let idx = *self.map.get(
180+
&syn::parse2::<Lifetime>(tokens.clone())
181+
.expect("goto! expects a lifetime label")
182+
.ident
183+
.to_string(),
184+
)?;
185+
let state = &self.state;
186+
let sm_label = &self.sm_label;
187+
Some(parse_quote!({ #state = #idx; continue #sm_label; }))
188+
}
189+
190+
fn recurse_into_inner_goto_block(&mut self, mac: &mut syn::Macro) -> bool {
191+
if mac.path.is_ident("switch") || mac.path.is_ident("goto_block") {
192+
if let Ok(mut inner) = syn::parse2::<Expr>(mac.tokens.clone()) {
193+
self.visit_expr_mut(&mut inner);
194+
mac.tokens = quote!(#inner);
195+
}
196+
return true;
197+
}
198+
false
199+
}
200+
}
201+
202+
impl VisitMut for GotoRewriter<'_> {
203+
fn visit_stmt_mut(&mut self, stmt: &mut Stmt) {
204+
if let Stmt::Macro(sm) = stmt {
205+
if sm.mac.path.is_ident("goto") {
206+
if let Some(jump) = self.expand_goto_into_state_machine_jump(&sm.mac.tokens) {
207+
*stmt = Stmt::Expr(jump, Some(Default::default()));
208+
}
209+
return;
210+
}
211+
if self.recurse_into_inner_goto_block(&mut sm.mac) {
212+
return;
213+
}
214+
}
215+
visit_mut::visit_stmt_mut(self, stmt);
216+
}
217+
}
218+
151219
// GotoStateMachine(dispatch arm + cases)
152220
pub struct SwitchStateMachine {
153221
pub goto: GotoStateMachine,

libcc2rs-macros/src/switch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use syn::parse::{Parse, ParseStream};
66
use syn::{Expr, Pat, parse_macro_input};
77

88
use crate::state_machine::{
9-
Arm, DispatchCase, GotoStateMachine, StateMachineNames, StateMachine, SwitchStateMachine,
9+
Arm, DispatchCase, GotoStateMachine, StateMachine, StateMachineNames, SwitchStateMachine,
1010
};
1111

1212
pub fn expand(input: TokenStream) -> TokenStream {

0 commit comments

Comments
 (0)