1use std::iter::empty;
2
3use arena_traits::{Arena, IndexIter};
4use cfg_traits::{Block as CFGBlock, Target as CFGTarget, Term as CFGTerm};
5use either::Either;
6use lending_iterator::prelude::*;
7use proc_macro2::{Span, TokenStream};
8use quasiquote::quasiquote;
9use quote::{format_ident, quote};
10use relooper::{BranchMode, RelooperLabel, ShapedBlock};
11use ssa_traits::{Block, Target, Term, TypedBlock, TypedFunc, TypedValue};
12use syn::{Ident, Lifetime};
13fn term(b: &BranchMode) -> TokenStream {
14 match b {
15 relooper::BranchMode::LoopBreak(l) => {
16 let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
17 quote! {
18 break #l;
19 }
20 }
21 relooper::BranchMode::LoopBreakIntoMulti(l) => {
22 let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
23 quote! {
24 break #l;
25 }
26 }
27 relooper::BranchMode::LoopContinue(l) => {
28 let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
29 quote! {
30 continue #l;
31 }
32 }
33 relooper::BranchMode::LoopContinueIntoMulti(l) => {
34 let l = Lifetime::new(&format!("'l{}", l), Span::call_site());
35 quote! {
36 continue #l;
37 }
38 }
39 relooper::BranchMode::MergedBranch => {
40 quote! {}
41 }
42 relooper::BranchMode::MergedBranchIntoMulti => quote! {},
43 relooper::BranchMode::SetLabelAndBreak => quote! {
44 break 'cff;
45 },
46 }
47}
48pub trait RsFunc:
49 TypedFunc<
50 Ty: Rs<Self>,
51 Block: RsId<Self> + Ord + Clone + RelooperLabel,
52 Value: RsId<Self> + Clone,
53 Values: Arena<Self::Value, Output: Rs<Self>>,
54 Blocks: Arena<Self::Block, Output: Block<Self, Terminator: RsTerm<Self>>>,
55 > + Sized
56{
57}
58impl<
59 T: TypedFunc<
60 Ty: Rs<Self>,
61 Block: RsId<Self> + Ord + Clone + RelooperLabel,
62 Value: RsId<Self> + Clone,
63 Values: Arena<Self::Value, Output: Rs<Self>>,
64 Blocks: Arena<Self::Block, Output: Block<Self, Terminator: RsTerm<Self>>>,
65 > + Sized,
66 > RsFunc for T
67{
68}
69pub trait Rs<F: RsFunc> {
70 fn rs(&self, f: &F) -> anyhow::Result<TokenStream>;
71}
72pub trait RsId<F: RsFunc> {
73 fn rs(&self, f: &F) -> anyhow::Result<Ident>;
74}
75pub trait RsTerm<F: RsFunc> {
76 fn rs_term(
77 &self,
78 f: &F,
79 go: impl FnMut(F::Block) -> anyhow::Result<TokenStream>,
80 ) -> anyhow::Result<TokenStream>;
81}
82pub fn render_target<R: RsFunc>(
83 t: &impl Target<R>,
84 f: &R,
85 go: &mut impl FnMut(R::Block) -> anyhow::Result<TokenStream>,
86 prepend: impl Iterator<Item: Rs<R>>,
87) -> anyhow::Result<TokenStream> {
88 let vars = prepend
89 .map(|x| x.rs(f))
90 .chain(
91 t.values(f)
92 .map::<HKT!(<'b> => anyhow::Result<TokenStream>), _>(|[], a| {
93 let a = format_ident!("V{}", a.rs(f)?);
94 anyhow::Ok(quasiquote!(#a .take()))
95 })
96 .into_iter(),
97 )
98 .enumerate()
99 .map(|(i, a)| {
100 let i = format_ident!("P{}_{i}", t.block().rs(f)?);
101 Ok(quasiquote! {
102 #i = #{a?};
103 })
104 })
105 .collect::<anyhow::Result<Vec<_>>>()?;
106 Ok(quasiquote! {
107 #(#vars);*
108 #{go(t.block())?}
109 })
110}
111pub fn go<F: RsFunc>(params: &[TokenStream], f: &F, e: F::Block) -> anyhow::Result<TokenStream> {
112 Ok(quasiquote! {
113 #{
114 let k = f.blocks().iter().flat_map(|a|{
115 if a == e{
116 Either::Left(params.iter().enumerate().map(move|(i,p)|Ok(quasiquote!(let mut #{format_ident!("P{}_{i}",a.rs(f)?)} = Some(#p)))))
117 }else{
118 Either::Right(f.blocks()[a].params().map(|(a,_)|a).enumerate().map(move|(i,t)|Ok(quasiquote!(let mut #{format_ident!("P{}_{i}",a.rs(f)?)}: Option<#{t.rs(f)?}> = None))).collect::<Vec<_>>().into_iter())
119 }
120 }).chain(f.values().iter().map(|v|{
121 let ty = f.values()[v.clone()].ty(f).rs(f)?;
122 Ok(quote!{
123 let mut #{format_ident!("V{}",v.rs(f)?)}: Option<#ty> = None;
124 })
125 })).collect::<anyhow::Result<Vec<_>>>()?;
126 quote! {
127 #(#k);*
128 }
129 };
130 let mut cff = 0usize;
131 #{block(f,ssa_reloop::go(f,e).as_ref())?}
132 })
133}
134pub fn idx_of<F: RsFunc>(f: &F, k: F::Block) -> usize {
135 f.blocks()
136 .iter()
137 .enumerate()
138 .find_map(|(i, l)| if l == k { Some(i) } else { None })
139 .unwrap()
140}
141pub fn block<F: RsFunc>(f: &F, k: &ShapedBlock<F::Block>) -> anyhow::Result<TokenStream> {
142 match k {
143 ShapedBlock::Loop(l) => {
144 let r = block(f, &l.inner.as_ref())?;
145 let next = l.next.as_ref();
146 let next = match next {
147 None => Default::default(),
148 Some(a) => block(f, a)?,
149 };
150 let l = Lifetime::new(&format!("'l{}", l.loop_id), Span::call_site());
151 Ok(quote! {
152 #l : loop{
153 #r
154 };
155 #next;
156 })
157 }
158 ShapedBlock::Multiple(k) => {
159 let initial = k.handled.iter().enumerate().flat_map(|(a, b)| {
160 b.labels.iter().map(move |l| {
161 let l = idx_of(f, *l);
162 quote! {
163 #l => #a
164 }
165 })
166 });
167 let cases = k
168 .handled
169 .iter()
170 .enumerate()
171 .map(|(a, i)| {
172 let ib = block(f, &i.inner)?;
173 let ic = if i.break_after {
174 quote! {}
175 } else {
176 quote! {
177 cff2 += 1;
178 continue 'cff
179 }
180 };
181 Ok(quote! {
182 #a => {
183 #ib;
184 #ic;
185 }
186 })
187 })
188 .collect::<anyhow::Result<Vec<_>>>()?;
189 Ok(quote! {
190 let mut cff2 = match cff{
191 #(#initial),*,
192 _ => unreachable!()
193 };
194 'cff: loop{
195 match cff2{
196 #(#cases),*,
197 _ => unreachable!()
198 };
199 break 'cff;
200 };
201 })
202 }
203 ShapedBlock::Simple(s) => {
204 let immediate = match s.immediate.as_ref() {
205 None => Default::default(),
206 Some(a) => block(f, a)?,
207 };
208
209 let next = match s.next.as_ref() {
210 None => Default::default(),
211 Some(a) => block(f, a)?,
212 };
213 let stmts = f.blocks()[s.label]
214 .insts()
215 .map(|v| {
216 Ok(quasiquote! {
217 #{format_ident!("V{}",v.rs(f)?)} = Some(#{f.values()[v].rs(f)?})
218 })
219 })
220 .collect::<anyhow::Result<Vec<_>>>()?;
221 let term = f.blocks()[s.label].term().rs_term(f, |k| {
222 let br = term(
223 &s.branches
224 .get(&k)
225 .cloned()
226 .unwrap_or(relooper::BranchMode::MergedBranch),
227 );
228 let bi = idx_of(f, k);
229 Ok(quote! {
230 cff = #bi;
231 #br
232 })
233 })?;
234 Ok(quote! {
235 #(#stmts);*;
236 #term;
237 #immediate;
238 #next;
239 })
240 }
241 }
242}
243#[cfg(feature = "id-arena")]
244impl<F: RsFunc, T> RsId<F> for id_arena::Id<T> {
245 fn rs(&self, f: &F) -> anyhow::Result<Ident> {
246 Ok(format_ident!("V{}", self.index()))
247 }
248}
249pub trait RsOp<F: RsFunc> {
250 fn rs_op(
251 &self,
252 f: &F,
253 all: &[impl RsId<F>],
254 blargs: &[F::Block],
255 ) -> anyhow::Result<TokenStream>;
256}
257#[cfg(feature = "ssa-canon")]
258impl<F: RsFunc<Block = id_arena::Id<ssa_canon::Block<O, T, Y>>>, O: RsOp<F>, T, Y> Rs<F>
259 for ssa_canon::Value<O, T, Y>
260{
261 fn rs(&self, f: &F) -> anyhow::Result<TokenStream> {
262 match self {
263 ssa_canon::Value::Op(o, args, q, _) => o.rs_op(f, &args, q.as_slice()),
264 ssa_canon::Value::Param(i, a, _) => {
265 Ok(quasiquote!(#{format_ident!("P{}_{i}",a.rs(f)?)}.take().unwrap()))
266 }
267 }
268 }
269}
270#[cfg(feature = "ssa-canon")]
271impl<
272 O: RsOp<ssa_canon::Func<O, T, Y>>,
273 T: Term<ssa_canon::Func<O, T, Y>, Target = ssa_canon::Target<O, T, Y>>,
274 Y: Clone,
275 > RsTerm<ssa_canon::Func<O, T, Y>> for ssa_canon::Target<O, T, Y>
276where
277 ssa_canon::Func<O, T, Y>: RsFunc<Block = id_arena::Id<ssa_canon::Block<O, T, Y>>>,
278{
279 fn rs_term(
280 &self,
281 f: &ssa_canon::Func<O, T, Y>,
282 mut go: impl FnMut(
283 <ssa_canon::Func<O, T, Y> as cfg_traits::Func>::Block,
284 ) -> anyhow::Result<TokenStream>,
285 ) -> anyhow::Result<TokenStream> {
286 render_target(self, f, &mut go, empty::<ssa_canon::Value<O, T, Y>>())
287 }
288}
289impl<F: RsFunc, A: RsOp<F>, B: RsOp<F>> RsOp<F> for Either<A, B> {
290 fn rs_op(
291 &self,
292 f: &F,
293 all: &[impl RsId<F>],
294 blargs: &[F::Block],
295 ) -> anyhow::Result<TokenStream> {
296 match self {
297 Either::Left(a) => a.rs_op(f, all, blargs),
298 Either::Right(b) => b.rs_op(f, all, blargs),
299 }
300 }
301}