1#![cfg_attr(not(any(test, feature = "std")), no_std)]
56
57use core::{fmt::Write, marker::PhantomData};
58
59pub mod builtins;
60pub mod ser_de;
61
62#[cfg(any(test, feature = "std"))]
63pub mod std_rt;
64
65#[cfg(any(test, feature = "std"))]
66pub mod compiler;
67
68pub mod nostd_rt;
69
70#[derive(Debug, Clone)]
71pub enum Error {
72 OutputFormat,
74
75 Input,
77
78 DataStackUnderflow,
80
81 StackOverflow,
83
84 DataStackEmpty,
86
87 RetStackEmpty,
89
90 FlowStackEmpty,
92
93 BadMath,
95
96 MissingIfPair,
98
99 MissingElsePair,
101
102 MissingLoopPair,
104
105 MissingDoPair,
107
108 InternalError,
110}
111
112impl From<core::fmt::Error> for Error {
113 fn from(_other: core::fmt::Error) -> Self {
114 Self::OutputFormat
115 }
116}
117
118pub enum WhichToken<BuiltinTok, SeqTok>
119where
120 SeqTok: Clone,
121 BuiltinTok: Clone,
122{
123 Single(BuiltinTok),
124 Ref(VerbSeqInner<SeqTok>),
125}
126
127#[derive(Debug, Clone, Eq, PartialEq)]
128pub struct VerbSeqInner<SeqTok>
129where
130 SeqTok: Clone,
131{
132 pub tok: SeqTok,
133 pub idx: usize,
134}
135
136impl<SeqTok> VerbSeqInner<SeqTok>
137where
138 SeqTok: Clone,
139{
140 pub fn from_word(tok: SeqTok) -> Self {
141 Self { tok, idx: 0 }
142 }
143}
144
145#[derive(Debug, Clone)]
146pub enum RuntimeWord<BuiltinTok, SeqTok>
147where
148 SeqTok: Clone,
149 BuiltinTok: Clone,
150{
151 LiteralVal(i32),
152
153 Verb(BuiltinTok),
155 VerbSeq(VerbSeqInner<SeqTok>),
156
157 UncondRelativeJump { offset: i32 },
158 CondRelativeJump { offset: i32, jump_on: bool },
159}
160
161impl<BuiltinTok, SeqTok> RuntimeWord<BuiltinTok, SeqTok>
162where
163 SeqTok: Clone,
164 BuiltinTok: Clone,
165{
166 pub fn as_seq_inner(&mut self) -> Result<&mut VerbSeqInner<SeqTok>, Error> {
167 match self {
168 RuntimeWord::VerbSeq(ref mut seq) => Ok(seq),
169 _ => Err(Error::InternalError),
170 }
171 }
172}
173
174pub struct Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>
175where
176 Sdata: Stack<Item = i32>,
177 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
178 SeqTok: Clone,
179 BuiltinTok: Clone,
180 O: Write,
181{
182 pub data_stk: Sdata,
183 pub ret_stk: Sdata,
184 pub flow_stk: Sexec,
185 pub _pd_ty_t_f: PhantomData<(BuiltinTok, SeqTok)>,
186 cur_output: O,
187}
188
189impl<Sdata, Sexec, BuiltinTok, SeqTok, O> Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>
190where
191 Sdata: Stack<Item = i32>,
192 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
193 SeqTok: Clone,
194 BuiltinTok: Clone,
195 O: Write,
196{
197 pub fn step(&mut self) -> Result<StepResult<BuiltinTok, SeqTok>, Error> {
198 match self.step_inner() {
199 Ok(r) => Ok(r),
200 Err(e) => {
201 while self.flow_stk.pop().is_ok() {}
202 while self.data_stk.pop().is_ok() {}
203 while self.ret_stk.pop().is_ok() {}
204 Err(e)
205 }
206 }
207 }
208
209 fn step_inner(&mut self) -> Result<StepResult<BuiltinTok, SeqTok>, Error> {
210 let ret = 'oloop: loop {
211 let cur = match self.flow_stk.last_mut() {
215 Ok(frame) => frame,
216 Err(_) => return Ok(StepResult::Done),
217 };
218
219 let mut jump = None;
220
221 let to_push = match cur {
222 RuntimeWord::LiteralVal(lit) => {
223 self.data_stk.push(*lit)?;
224 None
225 }
226 RuntimeWord::Verb(ft) => Some(WhichToken::Single(ft.clone())),
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) -> Result<(), Error>;
338 fn pop(&mut self) -> Result<Self::Item, Error>;
339 fn peek_back(&self, back: usize) -> Result<&Self::Item, Error>;
340 fn pop_back(&mut self, back: usize) -> Result<Self::Item, Error>;
341
342 fn last(&self) -> Result<&Self::Item, Error>;
344}
345
346pub trait ExecutionStack<BuiltinTok, SeqTok>
347where
348 SeqTok: Clone,
349 BuiltinTok: Clone,
350{
351 fn push(&mut self, data: RuntimeWord<BuiltinTok, SeqTok>);
352 fn pop(&mut self) -> Result<RuntimeWord<BuiltinTok, SeqTok>, Error>;
353 fn last_mut(&mut self) -> Result<&mut RuntimeWord<BuiltinTok, SeqTok>, Error>;
354}
355
356pub enum StepResult<BuiltinTok, SeqTok>
357where
358 SeqTok: Clone,
359 BuiltinTok: Clone,
360{
361 Done,
362 Working(WhichToken<BuiltinTok, SeqTok>),
363}
364
365#[cfg(test)]
366mod std_test {
367 use super::*;
368 use crate::std_rt::*;
369 use std::collections::BTreeMap;
370 use std::sync::Arc;
371
372 #[test]
373 fn foo() {
374 let mut x = new_runtime();
375
376 let mut fs_map: BTreeMap<String, StdFuncSeq> = BTreeMap::new();
377
378 fs_map.insert(
381 "star".into(),
382 StdFuncSeq {
383 inner: Arc::new(vec![
384 NamedStdRuntimeWord {
385 word: RuntimeWord::LiteralVal(42),
386 name: "42".into(),
387 },
388 NamedStdRuntimeWord {
389 word: RuntimeWord::Verb(BuiltinToken::new(builtins::bi_emit)),
390 name: "emit".into(),
391 },
392 ]),
393 },
394 );
395
396 fs_map.insert(
399 "mstar".into(),
400 StdFuncSeq {
401 inner: Arc::new(vec![
402 NamedStdRuntimeWord {
403 word: RuntimeWord::VerbSeq(VerbSeqInner::from_word("star".to_string())),
404 name: "star".into(),
405 },
406 NamedStdRuntimeWord {
407 word: RuntimeWord::LiteralVal(-1),
408 name: "-1".into(),
409 },
410 NamedStdRuntimeWord {
411 word: RuntimeWord::CondRelativeJump {
412 offset: 2,
413 jump_on: false,
414 },
415 name: "UCRJ".into(),
416 },
417 NamedStdRuntimeWord {
418 word: RuntimeWord::VerbSeq(VerbSeqInner::from_word("star".to_string())),
419 name: "star".into(),
420 },
421 NamedStdRuntimeWord {
422 word: RuntimeWord::VerbSeq(VerbSeqInner::from_word("star".to_string())),
423 name: "star".into(),
424 },
425 ]),
426 },
427 );
428
429 x.push_exec(RuntimeWord::VerbSeq(VerbSeqInner::from_word(
436 "mstar".to_string(),
437 )));
438
439 loop {
440 match x.step() {
441 Ok(StepResult::Done) => break,
442 Ok(StepResult::Working(WhichToken::Single(ft))) => {
443 ft.exec(&mut x).unwrap();
447 }
448 Ok(StepResult::Working(WhichToken::Ref(rtw))) => {
449 let c = fs_map
454 .get(&rtw.tok)
455 .and_then(|n| n.inner.get(rtw.idx))
456 .map(|n| n.clone().word);
457
458 x.provide_seq_tok(c).unwrap();
459 }
460 Err(_e) => todo!(),
461 }
462 }
463
464 let output = x.exchange_output();
465
466 assert_eq!("***", &output);
467 }
468}
469
470#[cfg(test)]
471mod nostd_test {
472 use super::*;
473 use crate::nostd_rt::*;
474 use heapless::{String, Vec};
475
476 #[test]
477 fn foo() {
478 let mut deser_dict: Vec<Vec<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 8>, 8> =
479 Vec::new();
480
481 deser_dict
484 .push({
485 let mut new: Vec<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 8> = Vec::new();
486 new.push(RuntimeWord::LiteralVal(42)).ok();
487 new.push(RuntimeWord::Verb(BuiltinToken::new(builtins::bi_emit)))
488 .ok();
489 new
490 })
491 .ok();
492
493 deser_dict
496 .push({
497 let mut new: Vec<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 8> = Vec::new();
498 new.push(RuntimeWord::VerbSeq(VerbSeqInner::from_word(0)))
499 .ok();
500 new.push(RuntimeWord::LiteralVal(-1)).ok();
501 new.push(RuntimeWord::CondRelativeJump {
502 offset: 2,
503 jump_on: false,
504 })
505 .ok();
506 new.push(RuntimeWord::VerbSeq(VerbSeqInner::from_word(0)))
507 .ok();
508 new.push(RuntimeWord::VerbSeq(VerbSeqInner::from_word(0)))
509 .ok();
510 new
511 })
512 .ok();
513
514 let idx = deser_dict;
516
517 let mut x = new_runtime::<32, 16, 256>();
518
519 let _sz = core::mem::size_of::<
532 Runtime<
533 BuiltinToken<32, 16, 256>,
534 usize,
535 HVecStack<i32, 32>,
536 HVecStack<RuntimeWord<BuiltinToken<32, 16, 256>, usize>, 16>,
537 String<256>,
538 >,
539 >();
540 x.push_exec(RuntimeWord::VerbSeq(
550 VerbSeqInner { tok: 1, idx: 0 },
552 ));
553
554 loop {
555 match x.step() {
556 Ok(StepResult::Done) => {
557 break;
558 }
559 Ok(StepResult::Working(WhichToken::Single(ft))) => {
560 ft.exec(&mut x).unwrap();
564 }
565 Ok(StepResult::Working(WhichToken::Ref(rtw))) => {
566 let c = idx
571 .get(rtw.tok)
572 .and_then(|n| n.get(rtw.idx))
573 .map(|n| n.clone());
574
575 x.provide_seq_tok(c).unwrap();
576 }
577 Err(_e) => todo!(),
578 }
579 }
580
581 let output = x.exchange_output();
582
583 assert_eq!("***", &output);
584 }
585}