verilog_arc/
lib.rs

1//  * ******************************************************************************************
2//  * Copyright (c) 2019 Pascal Kuthe. This file is part of the verilog-arc project.
3//  * It is subject to the license terms in the LICENSE file found in the top-level directory
4//  *  of this distribution and at  https://gitlab.com/DSPOM/verilogarc/blob/master/LICENSE.
5//  *  No part of verilog-arc, including this file, may be copied, modified, propagated, or
6//  *  distributed except according to the terms contained in the LICENSE file.
7//  * *******************************************************************************************
8
9pub use open_vaf;
10use open_vaf::ast::{UnaryOperator, VariableType};
11use open_vaf::cfg::{BasicBlockId, Terminator};
12use open_vaf::hir::{Block, DisciplineAccess};
13use open_vaf::ir::mir::RealExpression;
14use open_vaf::ir::*;
15use open_vaf::mir::ExpressionId;
16use open_vaf::mir::*;
17use open_vaf::ControlFlowGraph;
18use open_vaf::StringLiteral;
19use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
20use quote::*;
21
22pub struct RealNumberInterpolator(pub f64);
23impl ToTokens for RealNumberInterpolator {
24    fn to_tokens(&self, tokens: &mut TokenStream) {
25        match self.0 {
26            val if val.is_finite() => tokens.append(Literal::f64_suffixed(val)),
27            val if val == f64::INFINITY => quote!(f64::INFINITY).to_tokens(tokens),
28            val if val == f64::NEG_INFINITY => quote!(f64::NEG_INFINITY).to_tokens(tokens),
29            val if val.is_nan() => quote!(f64::NAN).to_tokens(tokens),
30            val => unreachable!(
31                "f64 can only be NAN, INFINITY, NEG_INFINITY or a finite number! {} didnt match any of these",
32                val
33            ),
34        }
35    }
36}
37
38pub struct ParameterTypeInterpolator<'lt>(pub &'lt ParameterType);
39impl<'lt> ToTokens for ParameterTypeInterpolator<'lt> {
40    fn to_tokens(&self, tokens: &mut TokenStream) {
41        match self.0 {
42            ParameterType::String { .. } => quote!(&str).to_tokens(tokens),
43            ParameterType::Real { .. } => quote!(f64).to_tokens(tokens),
44            ParameterType::Integer { .. } => quote!(i64).to_tokens(tokens),
45        }
46    }
47}
48
49pub struct CfgInterpolator<'lt, EI> {
50    pub mir: &'lt Mir,
51    pub cfg: &'lt ControlFlowGraph,
52    pub start: BasicBlockId,
53    pub end: Option<BasicBlockId>,
54    pub external_interpolator: &'lt EI,
55}
56impl<'lt, EI: TargetSpecificInterpolator> ToTokens for CfgInterpolator<'lt, EI> {
57    fn to_tokens(&self, tokens: &mut TokenStream) {
58        let mut current = self.start;
59        loop {
60            match self.end {
61                Some(end) if end == current => break,
62                _ => BasicBlockInterpolator {
63                    mir: self.mir,
64                    external_interpolator: self.external_interpolator,
65                    block: current,
66                    cfg: self.cfg,
67                }
68                .to_tokens(tokens),
69            }
70            match self.cfg.blocks[current].terminator {
71                Terminator::Goto(next) => current = next,
72                Terminator::End => break,
73                Terminator::Split {
74                    condition,
75                    true_block,
76                    false_block,
77                    merge,
78                } => {
79                    let condition = IntegerExpressionInterpolator {
80                        mir: self.mir,
81                        expression: condition,
82                        external_interpolator: self.external_interpolator,
83                    };
84
85                    if merge == current {
86                        //while loop
87                        let mut body = TokenStream::new();
88                        CfgInterpolator {
89                            mir: self.mir,
90                            start: true_block,
91                            end: Some(merge),
92                            cfg: self.cfg,
93                            external_interpolator: self.external_interpolator,
94                        }
95                        .to_tokens(&mut body);
96
97                        quote!(
98                            while (#condition) != 0 {
99                                #body
100                            }
101                        )
102                        .to_tokens(tokens);
103
104                        current = false_block;
105                    } else if merge == true_block {
106                        // if statement with empty if block
107                        let mut body = TokenStream::new();
108                        CfgInterpolator {
109                            mir: self.mir,
110                            start: false_block,
111                            end: Some(merge),
112                            cfg: self.cfg,
113                            external_interpolator: self.external_interpolator,
114                        }
115                        .to_tokens(&mut body);
116
117                        // condition == 0 is the opposite of condition != 0
118                        quote!(
119                            if (#condition) == 0 {
120                                #body
121                            }
122                        )
123                        .to_tokens(tokens);
124
125                        current = merge;
126                    } else if merge == false_block {
127                        // if statement with empty else
128                        let mut body = TokenStream::new();
129                        CfgInterpolator {
130                            mir: self.mir,
131                            start: true_block,
132                            end: Some(merge),
133                            cfg: self.cfg,
134                            external_interpolator: self.external_interpolator,
135                        }
136                        .to_tokens(&mut body);
137
138                        quote!(
139                            if (#condition) != 0 {
140                                #body
141                            }
142                        )
143                        .to_tokens(tokens);
144
145                        current = merge;
146                    } else {
147                        // if else statement
148                        let mut if_block = TokenStream::new();
149                        let mut else_block = TokenStream::new();
150
151                        CfgInterpolator {
152                            mir: self.mir,
153                            start: true_block,
154                            end: Some(merge),
155                            cfg: self.cfg,
156                            external_interpolator: self.external_interpolator,
157                        }
158                        .to_tokens(&mut if_block);
159
160                        CfgInterpolator {
161                            mir: self.mir,
162                            start: false_block,
163                            end: Some(merge),
164                            cfg: self.cfg,
165                            external_interpolator: self.external_interpolator,
166                        }
167                        .to_tokens(&mut else_block);
168
169                        quote!(
170                            if (#condition) != 0 {
171                                #if_block
172                            } else {
173                                #else_block
174                            }
175                        )
176                        .to_tokens(tokens);
177                        current = merge;
178                    }
179                }
180            }
181        }
182    }
183}
184
185pub struct BasicBlockInterpolator<'lt, EI> {
186    pub mir: &'lt Mir,
187    pub cfg: &'lt ControlFlowGraph,
188    pub block: BasicBlockId,
189    pub external_interpolator: &'lt EI,
190}
191
192impl<'lt, EI: TargetSpecificInterpolator> ToTokens for BasicBlockInterpolator<'lt, EI> {
193    fn to_tokens(&self, tokens: &mut TokenStream) {
194        for stmt in self.cfg.blocks[self.block].statements.iter().copied() {
195            match self.mir[stmt] {
196                Statement::Assignment(_, variable, value) => {
197                    let name = gen_variable_ident(variable);
198                    match value {
199                        ExpressionId::Real(value) => {
200                            let value = RealExpressionInterpolator {
201                                expression: value,
202                                mir: self.mir,
203                                external_interpolator: self.external_interpolator,
204                            };
205                            (quote! {#name = #value;}).to_tokens(tokens);
206                        }
207
208                        ExpressionId::Integer(value) => {
209                            let value = IntegerExpressionInterpolator {
210                                expression: value,
211                                mir: self.mir,
212                                external_interpolator: self.external_interpolator,
213                            };
214                            (quote! {#name = #value;}).to_tokens(tokens);
215                        }
216                        ExpressionId::String(_) => todo!("string expressions"),
217                    }
218                }
219
220                Statement::Contribute(attr, access, branch, val) => self
221                    .external_interpolator
222                    .contribute_to_tokens(self.mir, tokens, attr, access, branch, val),
223            }
224        }
225    }
226}
227
228pub trait TargetSpecificInterpolator: Sized {
229    #[allow(unused_variables)]
230    fn temperature_to_tokens(&self, mir: &Mir, tokens: &mut TokenStream) {
231        //By default temperature is just a variable
232        tokens.append(Ident::new("temperature", Span::call_site()))
233    }
234
235    #[allow(unused_variables)]
236    fn vt_to_tokens(
237        &self,
238        mir: &Mir,
239        tokens: &mut TokenStream,
240        arg: Option<RealExpressionInterpolator<'_, Self>>,
241    ) {
242        //By default temperature is just a variable and we are using the NIST2010 physical constants+
243        if let Some(arg) = arg {
244            quote!(1.3806488e-23 * #arg / 1.602176565e-19).to_tokens(tokens)
245        } else {
246            quote!(1.3806488e-23 * temperature / 1.602176565e-19).to_tokens(tokens)
247        }
248    }
249
250    fn simparam_to_tokens(
251        &self,
252        mir: &Mir,
253        tokens: &mut TokenStream,
254        name: StringExpressionId,
255        default: Option<RealExpressionInterpolator<'_, Self>>,
256    );
257
258    fn simparam_str_to_tokens(&self, mir: &Mir, tokens: &mut TokenStream, name: StringExpressionId);
259
260    fn param_given_to_tokens(&self, mir: &Mir, tokens: &mut TokenStream, param: ParameterId);
261
262    fn port_connected_to_tokens(&self, mir: &Mir, tokens: &mut TokenStream, port: PortId);
263
264    #[allow(unused_variables)]
265    fn limexp_to_tokens(
266        &self,
267        mir: &Mir,
268        tokens: &mut TokenStream,
269        arg: RealExpressionInterpolator<'_, Self>,
270    ) {
271        //Default to normal exp function
272        quote!(#arg.exp()).to_tokens(tokens)
273    }
274    fn noise_to_tokens(
275        &self,
276        mir: &Mir,
277        tokens: &mut TokenStream,
278        noise_source: NoiseSource<RealExpressionId, ()>,
279        source: Option<StringLiteral>,
280    );
281
282    fn contribute_to_tokens(
283        &self,
284        mir: &Mir,
285        tokens: &mut TokenStream,
286        attr: Attributes,
287        access: DisciplineAccess,
288        branch: BranchId,
289        val: RealExpressionId,
290    );
291}
292
293pub struct RealBuiltInFunctionCallInterpolator1p<'lt, EI> {
294    pub mir: &'lt Mir,
295    pub call: BuiltInFunctionCall1p,
296    pub arg: RealExpressionId,
297    pub external_interpolator: &'lt EI,
298}
299
300impl<'lt, EI: TargetSpecificInterpolator> ToTokens
301    for RealBuiltInFunctionCallInterpolator1p<'lt, EI>
302{
303    fn to_tokens(&self, tokens: &mut TokenStream) {
304        let arg = RealExpressionInterpolator {
305            mir: self.mir,
306            external_interpolator: self.external_interpolator,
307            expression: self.arg,
308        };
309        match self.call {
310            BuiltInFunctionCall1p::Sqrt => {
311                quote!(#arg.sqrt()).to_tokens(tokens);
312            }
313            BuiltInFunctionCall1p::Exp(false) => {
314                quote!(#arg.exp()).to_tokens(tokens);
315            }
316            BuiltInFunctionCall1p::Exp(true) => {
317                self.external_interpolator
318                    .limexp_to_tokens(self.mir, tokens, arg);
319            }
320            BuiltInFunctionCall1p::Ln => {
321                quote!(#arg.ln()).to_tokens(tokens);
322            }
323            BuiltInFunctionCall1p::Log => {
324                quote!(#arg.log10()).to_tokens(tokens);
325            }
326            BuiltInFunctionCall1p::Abs => {
327                quote!(#arg.abs()).to_tokens(tokens);
328            }
329            BuiltInFunctionCall1p::Floor => {
330                quote!(#arg.floor()).to_tokens(tokens);
331            }
332            BuiltInFunctionCall1p::Ceil => {
333                quote!(#arg.ceil()).to_tokens(tokens);
334            }
335            BuiltInFunctionCall1p::Sin => {
336                quote!(#arg.sin()).to_tokens(tokens);
337            }
338            BuiltInFunctionCall1p::Cos => {
339                quote!(#arg.cos()).to_tokens(tokens);
340            }
341            BuiltInFunctionCall1p::Tan => {
342                quote!(#arg.tan()).to_tokens(tokens);
343            }
344            BuiltInFunctionCall1p::ArcSin => {
345                quote!(#arg.asin()).to_tokens(tokens);
346            }
347            BuiltInFunctionCall1p::ArcCos => {
348                quote!(#arg.acos()).to_tokens(tokens);
349            }
350            BuiltInFunctionCall1p::ArcTan => {
351                quote!(#arg.atan()).to_tokens(tokens);
352            }
353            BuiltInFunctionCall1p::SinH => {
354                quote!(#arg.sinh()).to_tokens(tokens);
355            }
356            BuiltInFunctionCall1p::CosH => {
357                quote!(#arg.cosh()).to_tokens(tokens);
358            }
359            BuiltInFunctionCall1p::TanH => {
360                quote!(#arg.tanh()).to_tokens(tokens);
361            }
362            BuiltInFunctionCall1p::ArcSinH => {
363                quote!(#arg.asinh()).to_tokens(tokens);
364            }
365            BuiltInFunctionCall1p::ArcCosH => {
366                quote!(#arg.acosh()).to_tokens(tokens);
367            }
368            BuiltInFunctionCall1p::ArcTanH => {
369                quote!(#arg.atanh()).to_tokens(tokens);
370            }
371        }
372    }
373}
374
375pub struct RealBuiltInFunctionCallInterpolator2p<'lt, EI: TargetSpecificInterpolator> {
376    pub mir: &'lt Mir,
377    pub call: BuiltInFunctionCall2p,
378    pub arg1: RealExpressionId,
379    pub arg2: RealExpressionId,
380    pub external_interpolator: &'lt EI,
381}
382impl<'lt, EI: TargetSpecificInterpolator> ToTokens
383    for RealBuiltInFunctionCallInterpolator2p<'lt, EI>
384{
385    fn to_tokens(&self, tokens: &mut TokenStream) {
386        let arg1 = RealExpressionInterpolator {
387            mir: self.mir,
388            expression: self.arg1,
389            external_interpolator: self.external_interpolator,
390        };
391        let arg2 = RealExpressionInterpolator {
392            mir: self.mir,
393            expression: self.arg2,
394            external_interpolator: self.external_interpolator,
395        };
396        arg1.to_tokens(tokens);
397
398        match self.call {
399            BuiltInFunctionCall2p::Pow => {
400                quote! (.powf).to_tokens(tokens);
401            }
402            BuiltInFunctionCall2p::Hypot => {
403                quote! (.hypot).to_tokens(tokens);
404            }
405            BuiltInFunctionCall2p::Min => {
406                quote! (.min).to_tokens(tokens);
407            }
408            BuiltInFunctionCall2p::Max => {
409                quote! (.max).to_tokens(tokens);
410            }
411            BuiltInFunctionCall2p::ArcTan2 => {
412                quote! (.antan2).to_tokens(tokens);
413            }
414        }
415        quote!((#arg2)).to_tokens(tokens);
416    }
417}
418
419pub trait StatementInterpolatorFactory<'lt, 'out> {
420    type Interpolator: ToTokens;
421    fn new(&'lt self, stmt: StatementId, block: &'out mut Block) -> Self::Interpolator;
422}
423
424#[derive(Clone)]
425pub struct IntegerExpressionInterpolator<'lt, EI> {
426    pub mir: &'lt Mir,
427    pub expression: IntegerExpressionId,
428    pub external_interpolator: &'lt EI,
429}
430impl<'lt, EI: TargetSpecificInterpolator> ToTokens for IntegerExpressionInterpolator<'lt, EI> {
431    fn to_tokens(&self, tokens: &mut TokenStream) {
432        match self.mir[self.expression].contents {
433            IntegerExpression::Condition(condition, _, if_val, _, else_val) => {
434                let condition = IntegerExpressionInterpolator {
435                    expression: condition,
436                    ..*self
437                };
438                let if_val = IntegerExpressionInterpolator {
439                    expression: if_val,
440                    ..*self
441                };
442                let else_val = IntegerExpressionInterpolator {
443                    expression: else_val,
444                    ..*self
445                };
446                (quote! {
447                    if #condition != 0 {
448                        #if_val
449                    } else {
450                        #else_val
451                    }
452                })
453                .to_tokens(tokens)
454            }
455
456            IntegerExpression::Literal(val) => tokens.append(Literal::i64_suffixed(val)),
457
458            IntegerExpression::VariableReference(var_id) => {
459                tokens.append(gen_variable_ident(var_id))
460            }
461
462            IntegerExpression::ParameterReference(par_id) => {
463                tokens.append(gen_parameter_ident(par_id))
464            }
465
466            IntegerExpression::NetReference(_) | IntegerExpression::PortReference(_) => {
467                unimplemented!("Digital Nets")
468            }
469
470            IntegerExpression::FunctionCall(_, _) => unimplemented!("FunctionCalls"),
471
472            IntegerExpression::BinaryOperator(lhs, op, rhs) => {
473                let lhs = IntegerExpressionInterpolator {
474                    expression: lhs,
475                    ..*self
476                };
477                let rhs = IntegerExpressionInterpolator {
478                    expression: rhs,
479                    ..*self
480                };
481                match op.contents {
482                    IntegerBinaryOperator::Sum => quote! {(#lhs + #rhs)}.to_tokens(tokens),
483                    IntegerBinaryOperator::Subtract => quote! {(#lhs - #rhs)}.to_tokens(tokens),
484                    IntegerBinaryOperator::Multiply => quote! {(#lhs*#rhs)}.to_tokens(tokens),
485                    IntegerBinaryOperator::Divide => quote! {(#lhs/#rhs)}.to_tokens(tokens),
486                    IntegerBinaryOperator::Exponent => {
487                        (quote! {if #rhs >= 0 {#lhs.pow(#rhs)} else {0}}).to_tokens(tokens)
488                    }
489                    IntegerBinaryOperator::Modulus => quote! {(#lhs % #rhs)}.to_tokens(tokens),
490                    IntegerBinaryOperator::ShiftLeft => quote! {(#lhs << #rhs)}.to_tokens(tokens),
491                    IntegerBinaryOperator::ShiftRight => quote! {(#lhs >> #rhs)}.to_tokens(tokens),
492                    IntegerBinaryOperator::LogicOr => {
493                        (quote! {(((#lhs !=  0) || (#rhs != 0)) as i64)}).to_tokens(tokens)
494                    }
495                    IntegerBinaryOperator::LogicAnd => {
496                        (quote! {(((#lhs != 0) && (#rhs != 0)) as i64)}).to_tokens(tokens)
497                    }
498                    IntegerBinaryOperator::Xor => quote! {(#lhs ^ #rhs)}.to_tokens(tokens),
499                    IntegerBinaryOperator::NXor => quote! {!(#lhs ^ #rhs)}.to_tokens(tokens),
500                    IntegerBinaryOperator::And => quote! {(#lhs & #rhs)}.to_tokens(tokens),
501                    IntegerBinaryOperator::Or => quote! {(#lhs | #rhs)}.to_tokens(tokens),
502                }
503            }
504
505            IntegerExpression::RealComparison(lhs, op, rhs) => {
506                let lhs = RealExpressionInterpolator {
507                    expression: lhs,
508                    mir: self.mir,
509                    external_interpolator: self.external_interpolator,
510                };
511                let rhs = RealExpressionInterpolator {
512                    expression: rhs,
513                    mir: self.mir,
514                    external_interpolator: self.external_interpolator,
515                };
516                match op.contents {
517                    ComparisonOperator::LessThen => {
518                        (quote! {((#lhs < #rhs) as i64)}).to_tokens(tokens)
519                    }
520                    ComparisonOperator::LessEqual => {
521                        (quote! {((#lhs <= #rhs) as i64)}).to_tokens(tokens)
522                    }
523                    ComparisonOperator::GreaterThen => {
524                        (quote! {((#lhs > #rhs) as i64)}).to_tokens(tokens)
525                    }
526                    ComparisonOperator::GreaterEqual => {
527                        (quote! {((#lhs >= #rhs ) as i64)}).to_tokens(tokens)
528                    }
529                    ComparisonOperator::LogicEqual => {
530                        (quote! {((#lhs.approx_eq(#rhs, F64Margin::default())) as i64)})
531                            .to_tokens(tokens)
532                    }
533                    ComparisonOperator::LogicalNotEqual => {
534                        (quote! {((#lhs.approx_ne(#rhs, F64Margin::default())) as i64)})
535                            .to_tokens(tokens)
536                    }
537                }
538            }
539
540            IntegerExpression::IntegerComparison(lhs, op, rhs) => {
541                let lhs = IntegerExpressionInterpolator {
542                    expression: lhs,
543                    ..*self
544                };
545                let rhs = IntegerExpressionInterpolator {
546                    expression: rhs,
547                    ..*self
548                };
549                match op.contents {
550                    ComparisonOperator::LessThen => {
551                        (quote! {((#lhs < #rhs) as i64)}).to_tokens(tokens)
552                    }
553                    ComparisonOperator::LessEqual => {
554                        (quote! {((#lhs <= #rhs) as i64)}).to_tokens(tokens)
555                    }
556                    ComparisonOperator::GreaterThen => {
557                        (quote! {((#lhs > #rhs) as i64)}).to_tokens(tokens)
558                    }
559                    ComparisonOperator::GreaterEqual => {
560                        (quote! {((#lhs >= #rhs ) as i64)}).to_tokens(tokens)
561                    }
562                    ComparisonOperator::LogicEqual => {
563                        (quote! {((#lhs == #rhs) as i64)}).to_tokens(tokens)
564                    }
565                    ComparisonOperator::LogicalNotEqual => {
566                        (quote! {((#lhs != #rhs) as i64)}).to_tokens(tokens)
567                    }
568                }
569            }
570
571            IntegerExpression::UnaryOperator(op, expr) => {
572                let expr = IntegerExpressionInterpolator {
573                    expression: expr,
574                    ..*self
575                };
576                match op.contents {
577                    UnaryOperator::LogicNegate | UnaryOperator::BitNegate =>
578                    //these operators are the same in rust
579                    {
580                        (quote! {(!#expr)}).to_tokens(tokens)
581                    }
582                    UnaryOperator::ArithmeticNegate => quote! {(-#expr)}.to_tokens(tokens),
583                    UnaryOperator::ExplicitPositive => expr.to_tokens(tokens),
584                }
585            }
586
587            IntegerExpression::Abs(arg) => {
588                let arg = IntegerExpressionInterpolator {
589                    expression: arg,
590                    ..*self
591                };
592                (quote! {
593                    #arg.abs()
594                })
595                .to_tokens(tokens);
596            }
597
598            IntegerExpression::Min(arg1, arg2) => {
599                let arg1 = IntegerExpressionInterpolator {
600                    expression: arg1,
601                    ..*self
602                };
603                let arg2 = IntegerExpressionInterpolator {
604                    expression: arg2,
605                    ..*self
606                };
607                (quote! {
608                    #arg1.min(#arg2)
609                })
610                .to_tokens(tokens);
611            }
612
613            IntegerExpression::Max(arg1, arg2) => {
614                let arg1 = IntegerExpressionInterpolator {
615                    expression: arg1,
616                    ..*self
617                };
618                let arg2 = IntegerExpressionInterpolator {
619                    expression: arg2,
620                    ..*self
621                };
622                (quote! {
623                    #arg1.max(#arg2)
624                })
625                .to_tokens(tokens);
626            }
627
628            IntegerExpression::RealCast(expression) => {
629                let expression = RealExpressionInterpolator {
630                    expression,
631                    mir: self.mir,
632                    external_interpolator: self.external_interpolator,
633                };
634                (quote! {
635                    (#expression.round() as i64)
636                })
637                .to_tokens(tokens);
638            }
639
640            IntegerExpression::StringEq(lhs, rhs) => {
641                let lhs = StringExpressionInterpolator {
642                    mir: self.mir,
643                    expression: lhs,
644                    external_interpolator: self.external_interpolator,
645                };
646                let rhs = StringExpressionInterpolator {
647                    mir: self.mir,
648                    expression: rhs,
649                    external_interpolator: self.external_interpolator,
650                };
651                quote!((#lhs == #rhs) as i64).to_tokens(tokens)
652            }
653
654            IntegerExpression::StringNEq(lhs, rhs) => {
655                let lhs = StringExpressionInterpolator {
656                    mir: self.mir,
657                    expression: lhs,
658                    external_interpolator: self.external_interpolator,
659                };
660                let rhs = StringExpressionInterpolator {
661                    mir: self.mir,
662                    expression: rhs,
663                    external_interpolator: self.external_interpolator,
664                };
665                quote!((#lhs != #rhs) as i64).to_tokens(tokens)
666            }
667            IntegerExpression::ParamGiven(param) => self
668                .external_interpolator
669                .param_given_to_tokens(self.mir, tokens, param),
670            IntegerExpression::PortConnected(port) => self
671                .external_interpolator
672                .port_connected_to_tokens(self.mir, tokens, port),
673        }
674    }
675}
676
677#[derive(Clone)]
678pub struct StringExpressionInterpolator<'lt, EI> {
679    pub mir: &'lt Mir,
680    pub expression: StringExpressionId,
681    pub external_interpolator: &'lt EI,
682}
683impl<'lt, EI: TargetSpecificInterpolator> ToTokens for StringExpressionInterpolator<'lt, EI> {
684    fn to_tokens(&self, tokens: &mut TokenStream) {
685        match self.mir[self.expression].contents {
686            StringExpression::SimParam(name) => self
687                .external_interpolator
688                .simparam_str_to_tokens(self.mir, tokens, name),
689            StringExpression::Condition(cond, _, true_val, _, false_val) => {
690                let cond = IntegerExpressionInterpolator {
691                    mir: self.mir,
692                    expression: cond,
693                    external_interpolator: self.external_interpolator,
694                };
695
696                let true_val = StringExpressionInterpolator {
697                    mir: self.mir,
698                    expression: true_val,
699                    external_interpolator: self.external_interpolator,
700                };
701
702                let false_val = StringExpressionInterpolator {
703                    mir: self.mir,
704                    expression: false_val,
705                    external_interpolator: self.external_interpolator,
706                };
707
708                (quote! {
709                    if #cond != 0 {
710                        #true_val
711                    }else{
712                        #false_val
713                    }
714                })
715                .to_tokens(tokens)
716            }
717            StringExpression::Literal(val) => tokens.append(Literal::string(&val.as_str())),
718            StringExpression::VariableReference(var) => tokens.append(gen_variable_ident(var)),
719            StringExpression::ParameterReference(param) => {
720                tokens.append(gen_parameter_ident(param))
721            }
722        }
723    }
724}
725
726#[derive(Clone)]
727pub struct RealExpressionInterpolator<'lt, EI> {
728    pub mir: &'lt Mir,
729    pub expression: RealExpressionId,
730    pub external_interpolator: &'lt EI,
731}
732impl<'lt, EI: TargetSpecificInterpolator> ToTokens for RealExpressionInterpolator<'lt, EI> {
733    fn to_tokens(&self, tokens: &mut TokenStream) {
734        match self.mir[self.expression].contents {
735            RealExpression::Temperature => self
736                .external_interpolator
737                .temperature_to_tokens(self.mir, tokens),
738            RealExpression::Vt(arg) => self.external_interpolator.vt_to_tokens(
739                self.mir,
740                tokens,
741                arg.map(|arg| RealExpressionInterpolator {
742                    mir: self.mir,
743                    expression: arg,
744                    external_interpolator: self.external_interpolator,
745                }),
746            ),
747            RealExpression::SimParam(name, default) => {
748                self.external_interpolator.simparam_to_tokens(
749                    self.mir,
750                    tokens,
751                    name,
752                    default.map(|default| RealExpressionInterpolator {
753                        mir: self.mir,
754                        expression: default,
755                        external_interpolator: self.external_interpolator,
756                    }),
757                )
758            }
759            RealExpression::Condition(condition, _, if_val, _, else_val) => {
760                let condition = IntegerExpressionInterpolator {
761                    mir: self.mir,
762                    external_interpolator: self.external_interpolator,
763                    expression: condition,
764                };
765                let if_val = RealExpressionInterpolator {
766                    expression: if_val,
767                    ..*self
768                };
769                let else_val = RealExpressionInterpolator {
770                    expression: else_val,
771                    ..*self
772                };
773                (quote! {
774                    if #condition != 0 {
775                        #if_val
776                    }else {
777                        #else_val
778                    }
779                })
780                .to_tokens(tokens)
781            }
782
783            RealExpression::Literal(val) => RealNumberInterpolator(val).to_tokens(tokens),
784
785            RealExpression::BranchAccess(discipline_access, branch_access, order) => {
786                tokens.append(gen_branch_access(discipline_access, branch_access, order))
787            }
788
789            RealExpression::VariableReference(var_id) => tokens.append(gen_variable_ident(var_id)),
790
791            RealExpression::BuiltInFunctionCall2p(call, arg1, arg2) => {
792                let call = RealBuiltInFunctionCallInterpolator2p {
793                    mir: self.mir,
794                    call,
795                    arg1,
796                    arg2,
797                    external_interpolator: self.external_interpolator,
798                };
799                (quote! {(#call)}).to_tokens(tokens)
800            }
801            RealExpression::BuiltInFunctionCall1p(call, arg) => {
802                let call = RealBuiltInFunctionCallInterpolator1p {
803                    mir: self.mir,
804                    external_interpolator: self.external_interpolator,
805                    call,
806                    arg,
807                };
808                (quote! {(#call)}).to_tokens(tokens)
809            }
810
811            RealExpression::ParameterReference(par_id) => {
812                tokens.append(gen_parameter_ident(par_id))
813            }
814
815            RealExpression::BinaryOperator(lhs, op, rhs) => {
816                let lhs = RealExpressionInterpolator {
817                    expression: lhs,
818                    ..*self
819                };
820                let rhs = RealExpressionInterpolator {
821                    expression: rhs,
822                    ..*self
823                };
824                match op.contents {
825                    RealBinaryOperator::Sum => quote! {(#lhs + #rhs)}.to_tokens(tokens),
826                    RealBinaryOperator::Subtract => quote! {(#lhs - #rhs)}.to_tokens(tokens),
827                    RealBinaryOperator::Multiply => quote! {(#lhs*#rhs)}.to_tokens(tokens),
828                    RealBinaryOperator::Divide => quote! {(#lhs/#rhs)}.to_tokens(tokens),
829                    RealBinaryOperator::Exponent => quote! {(#lhs.powf(#rhs))}.to_tokens(tokens),
830                    RealBinaryOperator::Modulus => quote! {(#lhs % #rhs)}.to_tokens(tokens),
831                }
832            }
833
834            RealExpression::Negate(_, expression) => {
835                let expr = RealExpressionInterpolator {
836                    expression,
837                    ..*self
838                };
839                quote!((-#expr)).to_tokens(tokens)
840            }
841
842            RealExpression::IntegerConversion(expression) => {
843                let expression = IntegerExpressionInterpolator {
844                    expression,
845                    mir: self.mir,
846                    external_interpolator: self.external_interpolator,
847                };
848                (quote! {
849                    (#expression as f64)
850                })
851                .to_tokens(tokens);
852            }
853            RealExpression::Noise(source, name) => self
854                .external_interpolator
855                .noise_to_tokens(self.mir, tokens, source, name),
856        }
857    }
858}
859
860pub fn gen_branch_access(
861    discipline_access: DisciplineAccess,
862    branch_access: BranchId,
863    order: u8,
864) -> Ident {
865    Ident::new(
866        format!("branch_{:?}_{}_{}", discipline_access, branch_access, order).as_str(),
867        proc_macro2::Span::call_site(),
868    )
869}
870
871pub fn gen_parameter_ident(parameter: ParameterId) -> Ident {
872    Ident::new(
873        format!("parameter_{}", parameter).as_str(),
874        proc_macro2::Span::call_site(),
875    )
876}
877
878pub fn gen_variable_ident(id: VariableId) -> Ident {
879    Ident::new(
880        format!("variable_{}", id).as_str(),
881        proc_macro2::Span::call_site(),
882    )
883}
884
885pub fn gen_port_ident(port: PortId) -> Ident {
886    Ident::new(
887        format!("port_{}", port).as_str(),
888        proc_macro2::Span::call_site(),
889    )
890}
891
892pub fn generate_variable_type(variable_type: VariableType) -> TokenTree {
893    match variable_type {
894        VariableType::INTEGER => {
895            TokenTree::Ident(Ident::new("i32", proc_macro2::Span::call_site()))
896        }
897        VariableType::REAL => TokenTree::Ident(Ident::new("f64", proc_macro2::Span::call_site())),
898    }
899}
900
901pub fn gen_net_ident(net: NetId) -> Ident {
902    Ident::new(
903        format!("net_{}", net).as_str(),
904        proc_macro2::Span::call_site(),
905    )
906}