1use crate::error::SampleError;
4use crate::machine::renderer::{Binary, BufId, NodeRenderer, Site, SiteId, Unary};
5
6#[derive(Clone, Copy, Debug, PartialEq)]
7pub(crate) enum Op {
8 Const(f64),
9 Time,
10 Read { id: BufId, shift: i64 },
11 SelfAt { steps: u32 },
12 Add(usize),
13 Mul(usize),
14 Sub,
15 Div,
16 Pow,
17 Map(Unary),
18 Zip(Binary),
19 Crop { a: f64, b: f64 },
20 Join(usize),
21 Channel(usize),
22 Filter(SiteId),
23 Physics(SiteId),
24}
25
26#[derive(Clone, Debug, PartialEq)]
29pub struct Layout {
30 pub width: usize,
31 pub read_widths: Vec<usize>,
32 pub sites: Vec<Site>,
33}
34
35fn meet(a: usize, b: usize) -> Result<usize, SampleError> {
37 match (a, b) {
38 (a, b) if a == b => Ok(a),
39 (1, b) => Ok(b),
40 (a, 1) => Ok(a),
41 (left, right) => Err(SampleError::WidthMismatch { left, right }),
42 }
43}
44
45pub(crate) fn lower(
48 renderer: &NodeRenderer,
49 layout: &Layout,
50 ops: &mut Vec<Op>,
51 widths: &mut Vec<usize>,
52) -> Result<usize, SampleError> {
53 let push = |op: Op, width: usize, ops: &mut Vec<Op>, widths: &mut Vec<usize>| {
54 ops.push(op);
55 widths.push(width);
56 width
57 };
58 let w = match renderer {
59 NodeRenderer::Const(v) => push(Op::Const(*v), 1, ops, widths),
60 NodeRenderer::Time => push(Op::Time, 1, ops, widths),
61 NodeRenderer::Buffer { id, shift } => {
62 let width = layout.read_widths[id.0 as usize];
63 push(
64 Op::Read {
65 id: *id,
66 shift: *shift,
67 },
68 width,
69 ops,
70 widths,
71 )
72 }
73 NodeRenderer::SelfAt { steps } => {
74 push(Op::SelfAt { steps: *steps }, layout.width, ops, widths)
75 }
76 NodeRenderer::Add(parts) | NodeRenderer::Mul(parts) => {
77 let mut width = 1;
78 for p in parts {
79 width = meet(width, lower(p, layout, ops, widths)?)?;
80 }
81 let op = match renderer {
82 NodeRenderer::Add(_) => Op::Add(parts.len()),
83 _ => Op::Mul(parts.len()),
84 };
85 push(op, width, ops, widths)
86 }
87 NodeRenderer::Sub(a, b) | NodeRenderer::Div(a, b) | NodeRenderer::Pow(a, b) => {
88 let wa = lower(a, layout, ops, widths)?;
89 let wb = lower(b, layout, ops, widths)?;
90 let op = match renderer {
91 NodeRenderer::Sub(..) => Op::Sub,
92 NodeRenderer::Div(..) => Op::Div,
93 _ => Op::Pow,
94 };
95 push(op, meet(wa, wb)?, ops, widths)
96 }
97 NodeRenderer::Map(f, x) => {
98 let w = lower(x, layout, ops, widths)?;
99 push(Op::Map(*f), w, ops, widths)
100 }
101 NodeRenderer::Zip(f, a, b) => {
102 let wa = lower(a, layout, ops, widths)?;
103 let wb = lower(b, layout, ops, widths)?;
104 push(Op::Zip(*f), meet(wa, wb)?, ops, widths)
105 }
106 NodeRenderer::Crop { x, a, b } => {
107 let w = lower(x, layout, ops, widths)?;
108 push(Op::Crop { a: *a, b: *b }, w, ops, widths)
109 }
110 NodeRenderer::Join(parts) => {
111 let mut width = 0;
112 for p in parts {
113 width += lower(p, layout, ops, widths)?;
114 }
115 push(Op::Join(parts.len()), width, ops, widths)
116 }
117 NodeRenderer::Channel { x, k } => {
118 let w = lower(x, layout, ops, widths)?;
119 if *k >= w {
120 return Err(SampleError::ChannelOutOfRange { k: *k, width: w });
121 }
122 push(Op::Channel(*k), 1, ops, widths)
123 }
124 NodeRenderer::Filter {
125 site,
126 x,
127 cutoff,
128 q,
129 gain,
130 } => {
131 let mut width = lower(x, layout, ops, widths)?;
132 for arg in [cutoff, q, gain] {
133 width = meet(width, lower(arg, layout, ops, widths)?)?;
134 }
135 push(Op::Filter(*site), width, ops, widths)
136 }
137 NodeRenderer::Physics { site } => push(Op::Physics(*site), 1, ops, widths),
138 };
139 Ok(w)
140}