1mod cop;
17pub mod draw;
18pub mod io;
19mod mop;
20mod mop2;
21
22pub use cop::ConditionOp;
23pub use draw::{DrawInstr, Frozen};
24use enum_dispatch::enum_dispatch;
25pub use mop::MathOp1;
26pub use mop2::MathOp2;
27use std::{fmt, io::Write};
28
29use crate::debug::{info::DebugInfo, printable::Printable};
30
31use super::{
32 executor::{ExecutorContext, Instruction},
33 memory::{LAddress, LVar},
34};
35
36pub const OPS: &[&str] = &[
37 "equal",
38 "notEqual",
39 "lessThan",
40 "lessThanEq",
41 "greaterThan",
42 "greaterThanEq",
43 "strictEqual",
44 "always",
45 "add",
46 "sub",
47 "mul",
48 "div",
49 "idiv",
50 "mod",
51 "pow",
52 "land",
53 "not",
54 "shl",
55 "shr",
56 "or",
57 "and",
58 "xor",
59 "max",
60 "min",
61 "angle",
62 "angleDiff",
63 "len",
64 "noise",
65 "abs",
66 "log",
67 "log10",
68 "floor",
69 "ceil",
70 "sqrt",
71 "rand",
72 "sin",
73 "cos",
74 "tan",
75 "asin",
76 "acos",
77 "atan",
78];
79
80#[must_use = "to change control flow"]
81#[derive(Default)]
82pub enum Flow {
83 #[default]
84 Continue,
85 Stay,
86 Exit,
87}
88
89#[enum_dispatch]
90pub trait LInstruction: Printable {
91 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow;
92}
93
94#[derive(Debug, Copy, Clone)]
95#[enum_dispatch(LInstruction)]
96pub enum Instr {
97 Op2(Op2),
98 Jump(Jump),
99 AlwaysJump(AlwaysJump),
100 Set(Set),
101 Op1(Op1),
102 Read(io::Read),
103 Write(io::Write),
104 DrawFlush(draw::Flush),
105 DynJump(DynJump),
106 Print(io::Print),
107 Stop(Stop),
108 PackColor(PackColor),
109 Select(Select),
110 Noop(Noop),
111 End(End),
112}
113
114impl Printable for Instr {
115 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
116 match self {
117 Self::Op2(i) => i.print(info, f),
118 Self::Jump(i) => i.print(info, f),
119 Self::AlwaysJump(i) => i.print(info, f),
120 Self::Set(i) => i.print(info, f),
121 Self::Op1(i) => i.print(info, f),
122 Self::Read(i) => i.print(info, f),
123 Self::Write(i) => i.print(info, f),
124 Self::DrawFlush(i) => i.print(info, f),
125 Self::DynJump(i) => i.print(info, f),
126 Self::Print(i) => i.print(info, f),
127 Self::Stop(i) => i.print(info, f),
128 Self::End(i) => i.print(info, f),
129 Self::PackColor(i) => i.print(info, f),
130 Self::Select(i) => i.print(info, f),
131 Self::Noop(i) => i.print(info, f),
132 }
133 }
134}
135
136#[derive(Debug, Copy, Clone)]
137pub struct Set {
138 pub(crate) from: LAddress,
139 pub(crate) to: LAddress,
140}
141impl LInstruction for Set {
142 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
143 exec.set(self.from, self.to);
144 Flow::Continue
145 }
146}
147
148impl Printable for Set {
149 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
150 write!(f, "set {} {}", info[self.from], info[self.to])
151 }
152}
153
154macro_rules! op_enum {
155 ($v:vis enum $name:ident {
156 $($variant:ident),+ $(,)?
157 }) => {
158 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
159 $v enum $name {
160 $($variant),+
161 }
162
163 impl<'a> TryFrom<Token<'a>> for $name {
164 type Error = Token<'a>;
165 fn try_from(value: Token<'a>) -> Result<Self, Self::Error> {
166 match value {
167 $(Token::$variant => Ok(Self::$variant),)+
168 v => Err(v)
169 }
170 }
171 }
172
173 impl std::fmt::Display for $name {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
175 write!(f, "{}", Token::from(*self))
176 }
177 }
178
179 impl<'a> From<$name> for Token<'a> {
180 fn from(value: $name) -> Self {
181 match value {
182 $($name::$variant => Self::$variant,)+
183 }
184 }
185 }
186 }
187}
188use op_enum;
189
190macro_rules! op_impl {
192 ($name:ident, ptr type = $ptr:ty { $($own:ident => $fn:ident,)+ }) => {
193 impl $name {
194 pub const fn get_fn(self) -> $ptr {
195 match self {
196 $(Self::$own => $fn,)+
197 }
198 }
199 }
200
201 impl TryFrom<$ptr> for $name {
202 type Error = ();
203 fn try_from(f:$ptr) -> Result<Self, ()> {
204 match f {
205 $(f if f == $fn => Ok(Self::$own),)+
206 _ => Err(()),
207 }
208 }
209 }
210 }
211}
212use op_impl;
213
214macro_rules! get_num {
215 ($x:expr) => {
216 match $x {
217 LVar::Num(x) => *x,
218 _ => return Default::default(),
219 }
220 };
221}
222use get_num;
223
224#[derive(Debug, Copy, Clone)]
225pub struct Op1 {
226 op: for<'v> fn(&LVar<'v>) -> f64,
227 x: LAddress,
228 out: LAddress,
229}
230impl Op1 {
231 pub(crate) const fn new(op: MathOp1, x: LAddress, out: LAddress) -> Self {
232 Self {
233 op: op.get_fn(),
234 x,
235 out,
236 }
237 }
238}
239
240impl LInstruction for Op1 {
241 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
242 let x = (self.op)(exec.get(self.x));
243 *exec.get_mut(self.out) = LVar::Num(x);
244 Flow::Continue
245 }
246}
247
248impl Printable for Op1 {
249 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
250 let op = mop::MathOp1::try_from(self.op).unwrap();
251 write!(f, "op {op} {} {}", info[self.out], info[self.x])
252 }
253}
254
255#[derive(Debug, Copy, Clone)]
256pub struct Op2 {
257 op: for<'v> fn(&LVar<'v>, &LVar<'v>) -> f64,
258 a: LAddress,
259 b: LAddress,
260 out: LAddress,
261}
262impl Op2 {
263 pub(crate) const fn new(op: MathOp2, a: LAddress, b: LAddress, out: LAddress) -> Self {
264 Self {
265 op: op.get_fn(),
266 a,
267 b,
268 out,
269 }
270 }
271}
272
273impl LInstruction for Op2 {
274 #[inline]
275 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
276 let x = (self.op)(exec.get(self.a), exec.get(self.b));
277 exec.memory[self.out] = LVar::Num(x);
278 Flow::Continue
279 }
280}
281
282impl Printable for Op2 {
283 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
284 let op = mop2::MathOp2::try_from(self.op).unwrap();
285 write!(
286 f,
287 "op {op} {} {} {}",
288 info[self.out], info[self.a], info[self.b]
289 )
290 }
291}
292
293#[derive(Debug, Copy, Clone)]
294pub struct End {}
295
296impl LInstruction for End {
297 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
298 exec.iterations += 1;
299 unsafe { exec.jump(Instruction::new(0)) };
301 Flow::Stay
302 }
303}
304
305impl Printable for End {
306 fn print(&self, _: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
307 write!(f, "end")
308 }
309}
310
311#[derive(Debug, Copy, Clone)]
312pub struct Noop {}
313
314impl LInstruction for Noop {
315 fn run<W: Write>(&self, _: &mut ExecutorContext<'_, W>) -> Flow {
316 Flow::Continue
317 }
318}
319
320impl Printable for Noop {
321 fn print(&self, _: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
322 write!(f, "noop")
323 }
324}
325
326#[derive(Debug, Copy, Clone)]
327pub struct AlwaysJump {
328 pub(crate) to: Instruction,
329}
330impl LInstruction for AlwaysJump {
331 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
332 exec.jump(self.to);
333 Flow::Stay
334 }
335}
336
337impl Printable for AlwaysJump {
338 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
339 write!(f, "jump ")?;
340 match info.label(self.to) {
341 Some(l) => f.write_str(l)?,
342 None => write!(f, "{}", self.to.get())?,
343 }
344 write!(f, " always")
345 }
346}
347
348#[derive(Debug, Copy, Clone)]
349pub struct Jump {
350 op: for<'v> fn(&LVar<'v>, &LVar<'v>) -> bool,
351 pub(crate) to: Instruction,
352 a: LAddress,
353 b: LAddress,
354}
355impl Jump {
356 pub fn new(op: ConditionOp, to: Instruction, a: LAddress, b: LAddress) -> Self {
357 Self {
358 op: op.get_fn(),
359 to,
360 a,
361 b,
362 }
363 }
364}
365
366impl LInstruction for Jump {
367 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
368 if (self.op)(exec.get(self.a), exec.get(self.b)) {
369 exec.jump(self.to);
370 Flow::Stay
371 } else {
372 Flow::Continue
373 }
374 }
375}
376
377impl Printable for Jump {
378 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
379 let op = ConditionOp::try_from(self.op).unwrap();
380 write!(f, "jump {op} ")?;
381 match info.label(self.to) {
382 Some(l) => f.write_str(l)?,
383 None => write!(f, "{}", self.to.get())?,
384 };
385 write!(f, " {} {}", info[self.a], info[self.b])
386 }
387}
388
389#[derive(Debug, Copy, Clone)]
390pub struct DynJump {
391 pub to: LAddress,
392 pub proglen: usize,
393}
394
395impl LInstruction for DynJump {
396 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
397 if let &LVar::Num(n) = exec.get(self.to) {
398 let i = n.round() as usize;
399 if i < self.proglen {
400 exec.jump(unsafe { Instruction::new(i) });
402 return Flow::Stay;
403 }
404 }
405 Flow::Continue
406 }
407}
408
409impl Printable for DynJump {
410 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
411 write!(f, "set @counter {}", info[self.to])
412 }
413}
414
415#[derive(Debug, Copy, Clone)]
416pub struct Stop {}
417impl LInstruction for Stop {
418 fn run<W: Write>(&self, _: &mut ExecutorContext<'_, W>) -> Flow {
419 Flow::Exit
420 }
421}
422
423impl Printable for Stop {
424 fn print(&self, _: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
425 write!(f, "stop")
426 }
427}
428
429#[derive(Copy, Clone, Debug)]
430pub struct PackColor {
431 pub out: LAddress,
432 pub r: LAddress,
433 pub g: LAddress,
434 pub b: LAddress,
435 pub a: LAddress,
436}
437
438impl LInstruction for PackColor {
439 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
440 macro_rules! num {
441 ($($n:ident)+) => {
442 ($(match exec.memory[self.$n] {
443 LVar::Num(n) => (n.clamp(0.0, 1.0) * 255.0) as u8,
444 _ => 255,
445 },)+)
446 };
447 }
448 let (r, g, b, a) = num!(r g b a);
449 exec.memory[self.out] = LVar::from(fimg::Pack::pack(&[r, g, b, a]) as f64);
450 Flow::Continue
451 }
452}
453
454impl Printable for PackColor {
455 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
456 write!(
457 f,
458 "packcolor {} {} {} {} {}",
459 info[self.out], info[self.r], info[self.g], info[self.b], info[self.a]
460 )
461 }
462}
463#[derive(Debug, Copy, Clone)]
464pub struct Select {
465 pub op: for<'v> fn(&LVar<'v>, &LVar<'v>) -> bool,
466 pub(crate) to: LAddress,
467
468 pub x: LAddress,
469 pub y: LAddress,
470
471 pub a: LAddress,
472 pub b: LAddress,
473}
474
475impl LInstruction for Select {
476 fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow {
477 *exec.get_mut(self.to) = if (self.op)(exec.get(self.x), exec.get(self.y)) {
478 exec.get(self.a)
479 } else {
480 exec.get(self.b)
481 }
482 .clone();
483 Flow::Continue
484 }
485}
486
487impl Printable for Select {
488 fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result {
489 write!(
490 f,
491 "select {} {} {} {} {} {}",
492 info[self.to],
493 ConditionOp::try_from(self.op).unwrap(),
494 info[self.x],
495 info[self.y],
496 info[self.a],
497 info[self.b]
498 )
499 }
500}