1use crate::{exec::RtError::*, inst};
7use std::io::{Read, Write};
8
9inst!(
10 pub nop {}
17);
18
19inst!(
20 pub end (ctx) {
23 ctx.end = true;
24 }
25);
26
27inst!(
28 pub out (ctx, op) {
36 match op {
37 Null => {
38 let x = ctx.acc;
39
40 if x > 255 {
41 return Err(InvalidUtf8Byte(x));
42 }
43
44 #[allow(clippy::cast_possible_truncation)]
45 let out = x as u8;
46
47 ctx.io.write.write_all(&[out])?;
48 }
49 src if src.is_usizeable() => {
50 let src = ctx.read(src)?;
51
52 if src > 255 {
53 return Err(InvalidUtf8Byte(src));
54 }
55
56 #[allow(clippy::cast_possible_truncation)]
57 let out = src as u8;
58
59 ctx.io.write.write_all(&[out])?;
60 }
61 _ => return Err(InvalidOperand),
62 }
63 }
64);
65
66inst!(
67 pub inp (ctx, op) {
79 match op {
80 Null => {
81 let mut buf = [0; 1];
82
83 ctx.io.read.read_exact(&mut buf)?;
84
85 ctx.acc = buf[0] as usize;
86 }
87 dest if dest.is_read_write() => {
88 let mut buf = [0; 1];
89
90 ctx.io.read.read_exact(&mut buf)?;
91
92 ctx.modify(dest, |d| *d = buf[0] as usize)?;
93 }
94 _ => return Err(InvalidOperand),
95 }
96 }
97);
98
99inst!(
101 #[cfg(feature = "extended")]
108 pub dbg (ctx, op) {
109 let out = match op {
110 Null => format!("{ctx:?}"),
111 src if src.is_usizeable() => format!("{}", ctx.read(src)?),
112 MultiOp(ops) if ops.iter().all(inst::Op::is_usizeable) => ops
113 .iter()
114 .filter_map(|op| ctx.read(op).ok())
115 .enumerate()
116 .fold(String::new(), |acc, (idx, op)| {
117 if idx == ops.len() - 1 {
118 format!("{acc}{op}")
119 } else {
120 format!("{acc}{op}, ")
121 }
122 }),
123 MultiOp(_) => return Err(InvalidMultiOp),
124 _ => return Err(InvalidOperand),
125 };
126
127 writeln!(ctx.io.write, "{out}")?;
128 }
129);
130
131inst!(
133 #[cfg(feature = "extended")]
140 pub rin (ctx, op) {
141 use std::io::BufRead;
142 use super::RtResult;
143 const LF: u8 = 0xA;
144
145 fn input(inp: &mut impl BufRead) -> RtResult<usize> {
146 let mut buf = Vec::with_capacity(32);
147 inp.read_until(LF, &mut buf)?;
148
149 let str = String::from_utf8_lossy(&buf);
150 let str = str.trim();
151 let res = str.parse()
152 .map_err(|e| format!("Unable to parse {str:?} because {e}"))?;
153
154 Ok(res)
155 }
156
157 match op {
158 Null => ctx.acc = input(&mut ctx.io.read)?,
159 dest if dest.is_read_write() => {
160 let input = input(&mut ctx.io.read)?;
161 ctx.modify(dest, |d| *d = input)?;
162 }
163 _ => return Err(InvalidOperand),
164 }
165 }
166);
167
168inst!(
169 #[cfg(feature = "extended")]
174 pub call (ctx, op) {
175 match op {
176 &Addr(addr) => {
177 ctx.ret = ctx.mar + 1;
178 ctx.override_flow_control();
179 ctx.mar = addr;
180 }
181 _ => return Err(InvalidOperand),
182 }
183 }
184);
185
186inst!(
187 #[cfg(feature = "extended")]
192 pub ret (ctx) {
193 ctx.override_flow_control();
194 ctx.mar = ctx.ret;
195 }
196);