1#![cfg_attr(not(any(test, feature = "std")), no_std)]
57
58use core::{fmt::Write, marker::PhantomData};
59
60pub mod builtins;
61pub mod ser_de;
62
63#[cfg(any(test, feature = "std"))]
64pub mod std_rt;
65
66#[cfg(any(test, feature = "std"))]
67pub mod compiler;
68
69pub mod nostd_rt;
70
71#[derive(Debug, Clone)]
72pub enum Error {
73 OutputFormat,
75
76 Input,
78
79 DataStackUnderflow,
81
82 DataStackEmpty,
84
85 RetStackEmpty,
87
88 FlowStackEmpty,
90
91 BadMath,
93
94 MissingIfPair,
96
97 MissingElsePair,
99
100 MissingLoopPair,
102
103 MissingDoPair,
105
106 InternalError,
108}
109
110impl From<core::fmt::Error> for Error {
111 fn from(_other: core::fmt::Error) -> Self {
112 Self::OutputFormat
113 }
114}
115
116pub enum WhichToken<BuiltinTok, SeqTok>
117where
118 SeqTok: Clone,
119 BuiltinTok: Clone,
120{
121 Single(BuiltinTok),
122 Ref(VerbSeqInner<SeqTok>),
123}
124
125#[derive(Debug, Clone, Eq, PartialEq)]
126pub struct VerbSeqInner<SeqTok>
127where
128 SeqTok: Clone,
129{
130 pub tok: SeqTok,
131 pub idx: usize,
132}
133
134impl<SeqTok> VerbSeqInner<SeqTok>
135where
136 SeqTok: Clone,
137{
138 pub fn from_word(tok: SeqTok) -> Self {
139 Self { tok, idx: 0 }
140 }
141}
142
143#[derive(Debug, Clone)]
144pub enum RuntimeWord<BuiltinTok, SeqTok>
145where
146 SeqTok: Clone,
147 BuiltinTok: Clone,
148{
149 LiteralVal(i32),
150
151 Verb(BuiltinTok),
153 VerbSeq(VerbSeqInner<SeqTok>),
154
155 UncondRelativeJump { offset: i32 },
156 CondRelativeJump { offset: i32, jump_on: bool },
157}
158
159impl<BuiltinTok, SeqTok> RuntimeWord<BuiltinTok, SeqTok>
160where
161 SeqTok: Clone,
162 BuiltinTok: Clone,
163{
164 pub fn as_seq_inner(&mut self) -> Result<&mut VerbSeqInner<SeqTok>, Error> {
165 match self {
166 RuntimeWord::VerbSeq(ref mut seq) => Ok(seq),
167 _ => Err(Error::InternalError),
168 }
169 }
170}
171
172pub struct Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>
173where
174 Sdata: Stack<Item = i32>,
175 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
176 SeqTok: Clone,
177 BuiltinTok: Clone,
178 O: Write,
179{
180 pub data_stk: Sdata,
181 pub ret_stk: Sdata,
182 pub flow_stk: Sexec,
183 pub _pd_ty_t_f: PhantomData<(BuiltinTok, SeqTok)>,
184 cur_output: O,
185}
186
187impl<Sdata, Sexec, BuiltinTok, SeqTok, O> Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>
188where
189 Sdata: Stack<Item = i32>,
190 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
191 SeqTok: Clone,
192 BuiltinTok: Clone,
193 O: Write,
194{
195 pub fn step(&mut self) -> Result<StepResult<BuiltinTok, SeqTok>, Error> {
196 match self.step_inner() {
197 Ok(r) => Ok(r),
198 Err(e) => {
199 while self.flow_stk.pop().is_ok() {}
200 while self.data_stk.pop().is_ok() {}
201 while self.ret_stk.pop().is_ok() {}
202 Err(e)
203 }
204 }
205 }
206
207 fn step_inner(&mut self) -> Result<StepResult<BuiltinTok, SeqTok>, Error> {
208 let ret = 'oloop: loop {
209 let cur = match self.flow_stk.last_mut() {
213 Ok(frame) => frame,
214 Err(_) => return Ok(StepResult::Done),
215 };
216
217 let mut jump = None;
218
219 let to_push = match cur {
220 RuntimeWord::LiteralVal(lit) => {
221 self.data_stk.push(*lit);
222 None
223 }
224 RuntimeWord::Verb(ft) => {
225 Some(WhichToken::Single(ft.clone()))
226 }
227 RuntimeWord::VerbSeq(ref mut seq) => {
228 let ret = Some(WhichToken::Ref(seq.clone()));
232 seq.idx += 1;
233 ret
234 }
235 RuntimeWord::UncondRelativeJump { offset } => {
236 jump = Some(*offset);
237 None
238 }
239 RuntimeWord::CondRelativeJump { offset, jump_on } => {
240 let topvar = self.data_stk.pop()?;
241
242 let do_jump = (topvar == 0) ^ *jump_on;
250 if do_jump {
251 jump = Some(*offset);
252 }
253
254 None
255 }
256 };
257
258 match to_push {
259 Some(WhichToken::Single(ft)) => {
260 self.flow_stk.pop()?;
261 break 'oloop WhichToken::Single(ft);
262 }
263 Some(WhichToken::Ref(rf)) => {
264 break 'oloop WhichToken::Ref(rf);
265 }
266 None => {
267 self.flow_stk.pop()?;
268 }
269 }
270
271 if let Some(jump) = jump {
272 let new_cur = self.flow_stk.last_mut()?.as_seq_inner()?;
276
277 if jump < 0 {
278 let abs = jump.abs() as usize;
279
280 assert!(abs <= new_cur.idx);
281
282 new_cur.idx -= abs;
283 } else {
284 let abs = jump as usize;
285 assert_ne!(abs, 0);
286 new_cur.idx = new_cur.idx.checked_add(abs).ok_or(Error::BadMath)?;
287 }
288 }
289 };
290
291 Ok(StepResult::Working(ret))
292 }
293
294 pub fn provide_seq_tok(
295 &mut self,
296 seq: Option<RuntimeWord<BuiltinTok, SeqTok>>,
297 ) -> Result<(), Error> {
298 if let Some(mut word) = seq {
299 if let Ok(wd) = word.as_seq_inner() {
300 assert_eq!(wd.idx, 0);
301 wd.idx = 0;
302 }
303 self.flow_stk.push(word);
304 } else {
305 self.flow_stk.pop()?;
306 }
307 Ok(())
308 }
309
310 pub fn push_exec(&mut self, mut word: RuntimeWord<BuiltinTok, SeqTok>) {
311 if let Ok(wd) = word.as_seq_inner() {
312 assert_eq!(wd.idx, 0);
313 wd.idx = 0;
314 }
315 self.flow_stk.push(word);
316 }
317}
318
319impl<Sdata, Sexec, BuiltinTok, SeqTok, O> Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>
320where
321 Sdata: Stack<Item = i32>,
322 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
323 SeqTok: Clone,
324 BuiltinTok: Clone,
325 O: Write + Default,
326{
327 pub fn exchange_output(&mut self) -> O {
328 let mut new = O::default();
329 core::mem::swap(&mut new, &mut self.cur_output);
330 new
331 }
332}
333
334pub trait Stack {
335 type Item;
336
337 fn push(&mut self, data: Self::Item);
338 fn pop(&mut self) -> Result<Self::Item, Error>;
339
340 fn last(&self) -> Result<&Self::Item, Error>;
342}
343
344pub trait ExecutionStack<BuiltinTok, SeqTok>
345where
346 SeqTok: Clone,
347 BuiltinTok: Clone,
348{
349 fn push(&mut self, data: RuntimeWord<BuiltinTok, SeqTok>);
350 fn pop(&mut self) -> Result<RuntimeWord<BuiltinTok, SeqTok>, Error>;
351 fn last_mut(&mut self) -> Result<&mut RuntimeWord<BuiltinTok, SeqTok>, Error>;
352}
353
354pub enum StepResult<BuiltinTok, SeqTok>
355where
356 SeqTok: Clone,
357 BuiltinTok: Clone,
358{
359 Done,
360 Working(WhichToken<BuiltinTok, SeqTok>),
361}
362
363#[cfg(test)]
364mod std_test {
365 use super::*;
366 use crate::std_rt::*;
367 use std::collections::BTreeMap;
368 use std::sync::Arc;
369
370 #[test]
371 fn foo() {
372 let mut x = new_runtime();
373
374 let mut fs_map: BTreeMap<String, StdFuncSeq> = BTreeMap::new();
375
376 fs_map.insert(
379 "star".into(),
380 StdFuncSeq {
381 inner: Arc::new(vec![
382 NamedStdRuntimeWord {
383 word: RuntimeWord::LiteralVal(42),
384 name: "42".into(),
385 },
386 NamedStdRuntimeWord {
387 word: RuntimeWord::Verb(BuiltinToken::new(builtins::bi_emit)),
388 name: "emit".into(),
389 },
390 ]),
391 },
392 );
393
394 fs_map.insert(
397 "mstar".into(),
398 StdFuncSeq {
399 inner: Arc::new(vec![
400 NamedStdRuntimeWord {
401 word: RuntimeWord::VerbSeq(VerbSeqInner::from_word("star".to_string())),
402 name: "star".into(),
403 },
404 NamedStdRuntimeWord {
405 word: RuntimeWord::LiteralVal(-1),
406 name: "-1".into(),
407 },
408 NamedStdRuntimeWord {
409 word: RuntimeWord::CondRelativeJump {
410 offset: 2,
411 jump_on: false,
412 },
413 name: "UCRJ".into(),
414 },
415 NamedStdRuntimeWord {
416 word: RuntimeWord::VerbSeq(VerbSeqInner::from_word("star".to_string())),
417 name: "star".into(),
418 },
419 NamedStdRuntimeWord {
420 word: RuntimeWord::VerbSeq(VerbSeqInner::from_word("star".to_string())),
421 name: "star".into(),
422 },
423 ]),
424 },
425 );
426
427 x.push_exec(RuntimeWord::VerbSeq(VerbSeqInner::from_word(
434 "mstar".to_string(),
435 )));
436
437 loop {
438 match x.step() {
439 Ok(StepResult::Done) => break,
440 Ok(StepResult::Working(WhichToken::Single(ft))) => {
441 ft.exec(&mut x).unwrap();
445 }
446 Ok(StepResult::Working(WhichToken::Ref(rtw))) => {
447 let c = fs_map
452 .get(&rtw.tok)
453 .and_then(|n| n.inner.get(rtw.idx))
454 .map(|n| n.clone().word);
455
456 x.provide_seq_tok(c).unwrap();
457 }
458 Err(_e) => todo!(),
459 }
460 }
461
462 let output = x.exchange_output();
463
464 assert_eq!("***", &output);
465 }
466}
467
468#[cfg(test)]
469mod nostd_test {
470 use super::*;
471 use crate::nostd_rt::*;
472 use heapless::{String, Vec};
473
474 #[test]
475 fn foo() {
476 let mut deser_dict: Vec<Vec<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 8>, 8> =
477 Vec::new();
478
479 deser_dict
482 .push({
483 let mut new: Vec<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 8> = Vec::new();
484 new.push(RuntimeWord::LiteralVal(42)).ok();
485 new.push(RuntimeWord::Verb(BuiltinToken::new(builtins::bi_emit)))
486 .ok();
487 new
488 })
489 .ok();
490
491 deser_dict
494 .push({
495 let mut new: Vec<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 8> = Vec::new();
496 new.push(RuntimeWord::VerbSeq(VerbSeqInner::from_word(0)))
497 .ok();
498 new.push(RuntimeWord::LiteralVal(-1)).ok();
499 new.push(RuntimeWord::CondRelativeJump {
500 offset: 2,
501 jump_on: false,
502 })
503 .ok();
504 new.push(RuntimeWord::VerbSeq(VerbSeqInner::from_word(0)))
505 .ok();
506 new.push(RuntimeWord::VerbSeq(VerbSeqInner::from_word(0)))
507 .ok();
508 new
509 })
510 .ok();
511
512 let idx = deser_dict;
514
515 let mut x = new_runtime::<32, 16, 256>();
516
517 let _sz = core::mem::size_of::<
530 Runtime<
531 BuiltinToken<32, 16, 256>,
532 usize,
533 HVecStack<i32, 32>,
534 HVecStack<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 16>,
535 String<256>,
536 >,
537 >();
538 x.push_exec(RuntimeWord::VerbSeq(
548 VerbSeqInner { tok: 1, idx: 0 },
550 ));
551
552 loop {
553 match x.step() {
554 Ok(StepResult::Done) => {
555 break;
556 }
557 Ok(StepResult::Working(WhichToken::Single(ft))) => {
558 ft.exec(&mut x).unwrap();
562 }
563 Ok(StepResult::Working(WhichToken::Ref(rtw))) => {
564 let c = idx
569 .get(rtw.tok)
570 .and_then(|n| n.get(rtw.idx))
571 .map(|n| n.clone());
572
573 x.provide_seq_tok(c).unwrap();
574 }
575 Err(_e) => todo!(),
576 }
577 }
578
579 let output = x.exchange_output();
580
581 assert_eq!("***", &output);
582 }
583}