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) {
37 match op {
38 Null => {
39 ctx.io.write.write_all(&[ctx.acc.try_into().map_err(|_| InvalidUtf8Byte(ctx.acc))?])?;
40 }
41 src if src.is_usizeable() => {
42 let src = ctx.read(src)?;
43
44 ctx.io.write.write_all(&[src.try_into().map_err(|_| InvalidUtf8Byte(src))?])?;
45 }
46 MultiOp(ops) if ops.iter().all(inst::Op::is_usizeable) => for op in ops {
47 out(ctx, op)?;
48 }
49 _ => return Err(InvalidOperand),
50 }
51 }
52);
53
54inst!(
55 #[cfg(feature = "extended")]
60 pub print (ctx, op) {
61 match op {
62 MultiOp(ops) => match &ops[..] {
63 &[ref addr, Literal(n)] if addr.is_address() => {
64 let addr = ctx.as_address(addr)?;
65 let mut buf = Vec::with_capacity(n);
66
67 for address in addr..addr+n {
68 let byte = ctx.read(&Addr(address))?;
69
70 buf.push(byte.try_into().map_err(|_| InvalidUtf8Byte(byte))?);
71 }
72
73 ctx.io.write.write_all(&buf)?;
74 }
75 _ => return Err(InvalidMultiOp),
76 }
77 _ => return Err(InvalidOperand)
78 }
79 }
80);
81
82inst!(
83 pub inp (ctx, op) {
95 match op {
96 Null => {
97 let mut buf = [0; 1];
98
99 ctx.io.read.read_exact(&mut buf)?;
100
101 ctx.acc = buf[0] as usize;
102 }
103 dest if dest.is_read_write() => {
104 let mut buf = [0; 1];
105
106 ctx.io.read.read_exact(&mut buf)?;
107
108 ctx.modify(dest, |d| *d = buf[0] as usize)?;
109 }
110 _ => return Err(InvalidOperand),
111 }
112 }
113);
114
115inst!(
116 #[cfg(feature = "extended")]
121 pub read (ctx, op) {
122 match op {
123 MultiOp(ops) => match &ops[..] {
124 &[ref start, Literal(n)] if start.is_address() => {
125 let start = ctx.as_address(start)?;
126
127 let mut buf = Vec::with_capacity(n);
128
129 ctx.io.read.read_exact(&mut buf)?;
130
131 for (start, byte) in (start..start+n).zip(buf) {
132 ctx.modify(&Addr(start), |d| *d = byte as usize)?;
133 }
134 }
135 _ => return Err(InvalidMultiOp)
136 }
137 _ => return Err(InvalidOperand)
138 }
139 }
140);
141
142inst!(
144 #[cfg(feature = "extended")]
151 pub dbg (ctx, op) {
152 let out = match op {
153 Null => format!("{ctx:?}"),
154 src if src.is_usizeable() => format!("{}", ctx.read(src)?),
155 MultiOp(ops) if ops.iter().all(inst::Op::is_usizeable) => ops
156 .iter()
157 .filter_map(|op| ctx.read(op).ok())
158 .enumerate()
159 .fold(String::new(), |acc, (idx, op)| {
160 if idx == ops.len() - 1 {
161 format!("{acc}{op}")
162 } else {
163 format!("{acc}{op}, ")
164 }
165 }),
166 MultiOp(_) => return Err(InvalidMultiOp),
167 _ => return Err(InvalidOperand),
168 };
169
170 writeln!(ctx.io.write, "{out}")?;
171 }
172);
173
174inst!(
176 #[cfg(feature = "extended")]
183 pub rin (ctx, op) {
184 use std::io::BufRead;
185 use super::RtResult;
186 const LF: u8 = 0xA;
187
188 fn input(inp: &mut impl BufRead) -> RtResult<usize> {
189 let mut buf = Vec::with_capacity(32);
190 inp.read_until(LF, &mut buf)?;
191
192 let str = String::from_utf8_lossy(&buf);
193 let str = str.trim();
194 let res = str.parse()
195 .map_err(|e| format!("Unable to parse {str:?} because {e}"))?;
196
197 Ok(res)
198 }
199
200 match op {
201 Null => ctx.acc = input(&mut ctx.io.read)?,
202 dest if dest.is_read_write() => {
203 let input = input(&mut ctx.io.read)?;
204 ctx.modify(dest, |d| *d = input)?;
205 }
206 _ => return Err(InvalidOperand),
207 }
208 }
209);
210
211inst!(
212 #[cfg(feature = "extended")]
217 pub call (ctx, op) {
218 match op {
219 &Addr(addr) => {
220 ctx.ret = ctx.mar + 1;
221 ctx.override_flow_control();
222 ctx.mar = addr;
223 }
224 _ => return Err(InvalidOperand),
225 }
226 }
227);
228
229inst!(
230 #[cfg(feature = "extended")]
235 pub ret (ctx) {
236 ctx.override_flow_control();
237 ctx.mar = ctx.ret;
238 }
239);