1use im::{HashMap, Vector};
2use std::fmt::Display;
3use std::sync::Arc;
4
5use crate::tokens::Token;
6use crate::v1::log;
7
8#[derive(Clone)]
9pub struct RunConventions<'a> {
10 pub exe_name: &'a str,
11 pub exe_version: &'a str,
12 pub info_prefix: &'a str,
13 pub warn_prefix: &'a str,
14 pub error_prefix: &'a str,
15 pub fatal_prefix: &'a str,
16}
17
18#[derive(Clone)]
19pub enum RailError {
20 UnknownCommand(String),
21 StackUnderflow(RailState, String, Vec<RailType>),
22 TypeMismatch(Vec<RailType>, Vec<RailVal>),
23 CantEscape(Context),
24}
25
26impl std::fmt::Debug for RailError {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 Self::CantEscape(ctx) => write!(
30 f,
31 "Can't escape {}. This usually means there are too many closing brackets.",
32 match ctx {
33 Context::Main => "main context",
34 Context::None => "contextless scope",
35 Context::Quotation { parent_state: _ } => "quotation",
36 }
37 ),
38 Self::StackUnderflow(state, name, consumes) => write!(
39 f,
40 "Stack underflow. Stack had {} elements, but {} wanted {}",
41 state.len(),
42 name,
43 consumes.len()
44 ),
45 Self::TypeMismatch(types, values) => {
46 let values: Vec<RailType> = values.iter().map(|v| v.get_type()).collect();
47 write!(f, "Type mismatch. Wanted {:?} but had {:?}", types, values)
48 }
49 Self::UnknownCommand(cmd) => write!(f, "Unknown command: {}", cmd),
50 }
51 }
52}
53
54pub type RailRunResult = Result<RailState, (RailState, RailError)>;
55
56#[derive(Clone)]
57pub struct RailState {
58 pub stack: Stack,
60 pub definitions: Dictionary,
61 pub context: Context,
63 pub conventions: &'static RunConventions<'static>,
64}
65
66impl RailState {
67 pub fn new(
68 context: Context,
69 definitions: Dictionary,
70 conventions: &'static RunConventions,
71 ) -> RailState {
72 let stack = Stack::default();
73 RailState {
74 stack,
75 definitions,
76 context,
77 conventions,
78 }
79 }
80
81 pub fn new_main(definitions: Dictionary, conventions: &'static RunConventions) -> RailState {
82 RailState::new(Context::Main, definitions, conventions)
83 }
84
85 pub fn in_main(&self) -> bool {
86 matches!(self.context, Context::Main)
87 }
88
89 pub fn get_def(&self, name: &str) -> Option<RailDef> {
90 self.definitions.get(name).cloned()
91 }
92
93 pub fn child(&self) -> Self {
94 RailState {
95 stack: Stack::default(),
96 definitions: self.definitions.clone(),
97 context: Context::None,
98 conventions: self.conventions,
99 }
100 }
101
102 pub fn run_tokens(self, tokens: Vec<Token>) -> RailRunResult {
103 tokens.iter().fold(Ok(self), |state, term| {
104 state.and_then(|state| state.run_token(term.clone()))
105 })
106 }
107
108 pub fn run_token(self, token: Token) -> RailRunResult {
109 let res = match token {
110 Token::None => self,
111 Token::LeftBracket => self.deeper(),
112 Token::RightBracket => return self.higher(),
113 Token::String(s) => self.push_string(s),
114 Token::Boolean(b) => self.push_bool(b),
115 Token::I64(i) => self.push_i64(i),
116 Token::F64(f) => self.push_f64(f),
117 Token::DeferredTerm(term) => self.push_deferred_command(&term),
118 Token::Term(term) => match (self.clone().get_def(&term), self.in_main()) {
119 (Some(op), true) => {
120 return op.act(self);
121 }
122 (Some(op), false) => self.push_command(&op.name),
123 (None, false) => self.push_command(&term),
124 (None, true) => {
125 return Err((self, RailError::UnknownCommand(term.replace('\n', "\\n"))));
126 }
127 },
128 };
129
130 Ok(res)
131 }
132
133 pub fn run_val(self, value: RailVal, local_state: RailState) -> RailRunResult {
134 match value {
135 RailVal::Command(name) => {
136 let state = self.clone();
137 let cmd = state.get_def(&name).or_else(|| local_state.get_def(&name));
138
139 match cmd {
140 None => Err((self, RailError::UnknownCommand(name))),
141 Some(cmd) => cmd.act(self),
142 }
143 }
144 value => Ok(self.push(value)),
145 }
146 }
147
148 pub fn run_in_state(self, other_state: RailState) -> RailRunResult {
149 let values = self.stack.clone().values;
150 values
151 .into_iter()
152 .fold(Ok(other_state), |state, value| match state {
153 Ok(state) => state.run_val(value, self.child()),
154 err => err,
155 })
156 }
157
158 pub fn jailed_run_in_state(self, other_state: RailState) -> RailRunResult {
159 let jailed = |state: RailState| other_state.clone().replace_stack(state.stack);
160 self.run_in_state(other_state.clone())
161 .map(jailed)
162 .map_err(|(state, e)| (jailed(state), e))
163 }
164
165 pub fn update_stack(self, update: impl Fn(Stack) -> Stack) -> RailState {
166 RailState {
167 stack: update(self.stack),
168 definitions: self.definitions,
169 context: self.context,
170 conventions: self.conventions,
171 }
172 }
173
174 pub fn update_stack_and_defs(
175 self,
176 update: impl Fn(Stack, Dictionary) -> (Stack, Dictionary),
177 ) -> RailState {
178 let (stack, definitions) = update(self.stack, self.definitions);
179 RailState {
180 stack,
181 definitions,
182 context: self.context,
183 conventions: self.conventions,
184 }
185 }
186
187 pub fn replace_stack(self, stack: Stack) -> RailState {
188 RailState {
189 stack,
190 definitions: self.definitions,
191 context: self.context,
192 conventions: self.conventions,
193 }
194 }
195
196 pub fn replace_definitions(self, definitions: Dictionary) -> RailState {
197 RailState {
198 stack: self.stack,
199 definitions,
200 context: self.context,
201 conventions: self.conventions,
202 }
203 }
204
205 pub fn replace_context(self, context: Context) -> RailState {
206 RailState {
207 stack: self.stack,
208 definitions: self.definitions,
209 context,
210 conventions: self.conventions,
211 }
212 }
213
214 pub fn deeper(self) -> Self {
215 let conventions = self.conventions;
216 RailState {
217 stack: Stack::default(),
218 definitions: self.definitions.clone(),
219 context: Context::Quotation {
220 parent_state: Box::new(self),
221 },
222 conventions,
223 }
224 }
225
226 pub fn higher(self) -> RailRunResult {
227 match self.context.clone() {
228 Context::Quotation { parent_state } => Ok(parent_state.push_quote(self)),
229 context => Err((self, RailError::CantEscape(context))),
230 }
231 }
232
233 pub fn len(&self) -> usize {
234 self.stack.len()
235 }
236
237 pub fn is_empty(&self) -> bool {
238 self.stack.is_empty()
239 }
240
241 pub fn reverse(self) -> Self {
242 self.update_stack(|stack| stack.reverse())
243 }
244
245 pub fn push(self, term: RailVal) -> Self {
246 self.update_stack(|stack| stack.push(term.clone()))
247 }
248
249 pub fn push_bool(self, b: bool) -> Self {
250 self.push(RailVal::Boolean(b))
251 }
252
253 pub fn push_i64(self, i: i64) -> Self {
254 self.push(RailVal::I64(i))
255 }
256
257 pub fn push_f64(self, n: f64) -> Self {
258 self.push(RailVal::F64(n))
259 }
260
261 pub fn push_command(self, op_name: &str) -> Self {
262 self.push(RailVal::Command(op_name.to_owned()))
263 }
264
265 pub fn push_deferred_command(self, op_name: &str) -> Self {
266 self.push(RailVal::DeferredCommand(op_name.to_owned()))
267 }
268
269 pub fn push_quote(self, quote: RailState) -> Self {
270 self.push(RailVal::Quote(quote))
271 }
272
273 pub fn push_stab(self, st: Stab) -> Self {
274 self.push(RailVal::Stab(st))
275 }
276
277 pub fn push_string(self, s: String) -> Self {
278 self.push(RailVal::String(s))
279 }
280
281 pub fn push_str(self, s: &str) -> Self {
282 self.push(RailVal::String(s.to_owned()))
283 }
284
285 pub fn pop(self) -> (RailVal, Self) {
286 let (value, stack) = self.stack.clone().pop();
287 (value, self.replace_stack(stack))
288 }
289
290 pub fn pop_bool(self, context: &str) -> (bool, Self) {
291 let (value, quote) = self.pop();
292 match value {
293 RailVal::Boolean(b) => (b, quote),
294 _ => panic!("{}", log::type_panic_msg(context, "bool", value)),
295 }
296 }
297
298 pub fn pop_i64(self, context: &str) -> (i64, Self) {
299 let (value, quote) = self.pop();
300 match value {
301 RailVal::I64(n) => (n, quote),
302 rail_val => panic!("{}", log::type_panic_msg(context, "i64", rail_val)),
303 }
304 }
305
306 pub fn pop_f64(self, context: &str) -> (f64, Self) {
307 let (value, quote) = self.pop();
308 match value {
309 RailVal::F64(n) => (n, quote),
310 rail_val => panic!("{}", log::type_panic_msg(context, "f64", rail_val)),
311 }
312 }
313
314 fn _pop_command(self, context: &str) -> (String, Self) {
315 let (value, quote) = self.pop();
316 match value {
317 RailVal::Command(op) => (op, quote),
318 RailVal::DeferredCommand(op) => (op, quote),
319 rail_val => panic!("{}", log::type_panic_msg(context, "command", rail_val)),
320 }
321 }
322
323 pub fn pop_quote(self, context: &str) -> (RailState, Self) {
324 let (value, quote) = self.pop();
325 match value {
326 RailVal::Quote(subquote) => (subquote, quote),
327 rail_val => panic!("{}", log::type_panic_msg(context, "quote", rail_val)),
330 }
331 }
332
333 pub fn pop_stab(self, context: &str) -> (Stab, Self) {
334 let (value, quote) = self.pop();
335 match value {
336 RailVal::Stab(s) => (s, quote),
337 rail_val => panic!("{}", log::type_panic_msg(context, "string", rail_val)),
340 }
341 }
342
343 pub fn pop_stab_entry(self, context: &str) -> (String, RailVal, Self) {
344 let (original_entry, quote) = self.pop_quote(context);
345 let (value, entry) = original_entry.clone().stack.pop();
346 let (key, entry) = entry.pop_string(context);
347
348 if !entry.is_empty() {
349 panic!(
350 "{}",
351 log::type_panic_msg(context, "[ string a ]", RailVal::Quote(original_entry))
352 );
353 }
354
355 (key, value, quote)
356 }
357
358 pub fn pop_string(self, context: &str) -> (String, Self) {
359 let (value, quote) = self.pop();
360 match value {
361 RailVal::String(s) => (s, quote),
362 rail_val => panic!("{}", log::type_panic_msg(context, "string", rail_val)),
363 }
364 }
365
366 pub fn enqueue(self, value: RailVal) -> Self {
367 let stack = self.stack.clone().enqueue(value);
368 self.replace_stack(stack)
369 }
370
371 pub fn dequeue(self) -> (RailVal, Self) {
372 let (value, stack) = self.stack.clone().dequeue();
373 (value, self.replace_stack(stack))
374 }
375}
376
377#[derive(Clone)]
378pub enum Context {
379 Main,
380 Quotation { parent_state: Box<RailState> },
381 None,
382}
383
384#[derive(Clone, Debug)]
385pub enum RailType {
386 A,
387 B,
388 C,
389 Unknown,
391 Boolean,
392 Number,
393 I64,
394 F64,
395 Command,
396 Quote,
400 QuoteOrCommand,
401 QuoteOrString,
402 String,
403 Stab,
404}
405
406impl Display for RailType {
407 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
408 use RailType::*;
409 let my_type = match self {
410 A => "a",
411 B => "b",
412 C => "c",
413 Unknown => "...",
414 Boolean => "bool",
415 Number => "num",
416 I64 => "i64",
417 F64 => "f64",
418 Command => "command",
419 Quote => "quote",
420 QuoteOrCommand => "quote|command",
421 QuoteOrString => "quote|string",
422 String => "string",
423 Stab => "stab",
424 };
425
426 write!(fmt, "{}", my_type)
427 }
428}
429
430#[derive(Clone)]
431pub enum RailVal {
432 Boolean(bool),
433 I64(i64),
435 F64(f64),
436 Command(String),
437 DeferredCommand(String),
438 Quote(RailState),
439 String(String),
440 Stab(Stab),
441}
442
443impl PartialEq for RailVal {
444 fn eq(&self, other: &Self) -> bool {
445 use RailVal::*;
446 match (self, other) {
447 (Boolean(a), Boolean(b)) => a == b,
448 (I64(a), I64(b)) => a == b,
449 (I64(a), F64(b)) => *a as f64 == *b,
450 (F64(a), I64(b)) => *a == *b as f64,
451 (F64(a), F64(b)) => a == b,
452 (String(a), String(b)) => a == b,
453 (Command(a), Command(b)) => a == b,
454 (DeferredCommand(a), DeferredCommand(b)) => a == b,
455 (Quote(a), Quote(b)) => a.stack == b.stack,
457 (Stab(a), Stab(b)) => a == b,
458 _ => false,
459 }
460 }
461}
462
463impl RailVal {
464 pub fn type_name(&self) -> String {
465 self.get_type().to_string()
466 }
467
468 fn get_type(&self) -> RailType {
469 match self {
470 RailVal::Boolean(_) => RailType::Boolean,
471 RailVal::I64(_) => RailType::I64,
472 RailVal::F64(_) => RailType::F64,
473 RailVal::Command(_) => RailType::Command,
474 RailVal::DeferredCommand(_) => RailType::Command,
475 RailVal::Quote(_) => RailType::Quote,
476 RailVal::String(_) => RailType::String,
477 RailVal::Stab(_) => RailType::Stab,
478 }
479 }
480
481 pub fn into_command_list(self) -> Vec<RailVal> {
482 match &self {
483 RailVal::Command(_) => vec![self],
484 RailVal::DeferredCommand(_) => vec![self],
485 RailVal::String(s) => vec![RailVal::Command(s.into())],
486 RailVal::Quote(q) => q
487 .clone()
488 .stack
489 .values
490 .into_iter()
491 .flat_map(|v| v.into_command_list())
492 .collect(),
493 _ => unimplemented!(),
494 }
495 }
496
497 pub fn into_state(self, state: &RailState) -> RailState {
498 match &self {
499 RailVal::Quote(q) => q.clone(),
500 _ => state.child().push(self),
501 }
502 }
503}
504
505impl std::fmt::Display for RailVal {
506 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
507 use RailVal::*;
508 match self {
509 Boolean(b) => write!(fmt, "{}", if *b { "true" } else { "false" }),
510 I64(n) => write!(fmt, "{}", n),
511 F64(n) => write!(fmt, "{}", n),
512 Command(cmd) => write!(fmt, "{}", cmd),
513 DeferredCommand(cmd) => write!(fmt, "\\{}", cmd),
514 Quote(q) => write!(fmt, "{}", q.stack),
515 String(s) => write!(fmt, "\"{}\"", s.replace('\n', "\\n")),
516 Stab(t) => {
517 write!(fmt, "[ ").unwrap();
518
519 for (k, v) in t.iter() {
520 write!(fmt, "[ \"{}\" {} ] ", k, v).unwrap();
521 }
522
523 write!(fmt, "]")
524 }
525 }
526 }
527}
528
529#[derive(Clone)]
530pub struct Stack {
531 pub values: Vector<RailVal>,
532}
533
534impl PartialEq for Stack {
535 fn eq(&self, other: &Self) -> bool {
537 self.values
538 .clone()
539 .into_iter()
540 .zip(other.values.clone())
541 .all(|(a, b)| a == b)
542 }
543}
544
545impl Stack {
546 pub fn new(values: Vector<RailVal>) -> Self {
547 Stack { values }
548 }
549
550 pub fn of(value: RailVal) -> Self {
551 let mut values = Vector::default();
552 values.push_back(value);
553 Stack { values }
554 }
555
556 pub fn len(&self) -> usize {
557 self.values.len()
558 }
559
560 pub fn is_empty(&self) -> bool {
561 self.values.is_empty()
562 }
563
564 pub fn reverse(&self) -> Stack {
565 let values = self.values.iter().rev().cloned().collect();
566 Stack::new(values)
567 }
568
569 pub fn push(mut self, term: RailVal) -> Stack {
570 self.values.push_back(term);
571 self
572 }
573
574 pub fn pop(mut self) -> (RailVal, Stack) {
575 let term = self.values.pop_back().unwrap();
576 (term, self)
577 }
578
579 pub fn pop_bool(self, context: &str) -> (bool, Stack) {
580 let (value, quote) = self.pop();
581 match value {
582 RailVal::Boolean(b) => (b, quote),
583 _ => panic!("{}", log::type_panic_msg(context, "bool", value)),
584 }
585 }
586
587 pub fn pop_i64(self, context: &str) -> (i64, Stack) {
588 let (value, quote) = self.pop();
589 match value {
590 RailVal::I64(n) => (n, quote),
591 rail_val => panic!("{}", log::type_panic_msg(context, "i64", rail_val)),
592 }
593 }
594
595 pub fn pop_f64(self, context: &str) -> (f64, Stack) {
596 let (value, quote) = self.pop();
597 match value {
598 RailVal::F64(n) => (n, quote),
599 rail_val => panic!("{}", log::type_panic_msg(context, "f64", rail_val)),
600 }
601 }
602
603 fn _pop_command(self, context: &str) -> (String, Stack) {
604 let (value, quote) = self.pop();
605 match value {
606 RailVal::Command(op) => (op, quote),
607 RailVal::DeferredCommand(op) => (op, quote),
608 rail_val => panic!("{}", log::type_panic_msg(context, "command", rail_val)),
609 }
610 }
611
612 pub fn pop_quote(self, context: &str) -> (RailState, Stack) {
613 let (value, quote) = self.pop();
614 match value {
615 RailVal::Quote(subquote) => (subquote, quote),
616 rail_val => panic!("{}", log::type_panic_msg(context, "quote", rail_val)),
619 }
620 }
621
622 pub fn pop_stab(self, context: &str) -> (Stab, Stack) {
623 let (value, quote) = self.pop();
624 match value {
625 RailVal::Stab(s) => (s, quote),
626 rail_val => panic!("{}", log::type_panic_msg(context, "string", rail_val)),
629 }
630 }
631
632 pub fn pop_stab_entry(self, context: &str) -> (String, RailVal, Stack) {
633 let (original_entry, quote) = self.pop_quote(context);
634 let (value, entry) = original_entry.clone().stack.pop();
635 let (key, entry) = entry.pop_string(context);
636
637 if !entry.is_empty() {
638 panic!(
639 "{}",
640 log::type_panic_msg(context, "[ string a ]", RailVal::Quote(original_entry))
641 );
642 }
643
644 (key, value, quote)
645 }
646
647 pub fn pop_string(self, context: &str) -> (String, Stack) {
648 let (value, quote) = self.pop();
649 match value {
650 RailVal::String(s) => (s, quote),
651 rail_val => panic!("{}", log::type_panic_msg(context, "string", rail_val)),
652 }
653 }
654
655 pub fn enqueue(mut self, value: RailVal) -> Stack {
656 self.values.push_front(value);
657 self
658 }
659
660 pub fn dequeue(mut self) -> (RailVal, Stack) {
661 let value = self.values.pop_front().unwrap();
662 (value, self)
663 }
664}
665
666impl Default for Stack {
667 fn default() -> Self {
668 Self::new(Vector::default())
669 }
670}
671
672impl std::fmt::Display for Stack {
673 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
674 write!(f, "[ ").unwrap();
675
676 for term in &self.values {
677 write!(f, "{} ", term).unwrap();
678 }
679
680 write!(f, "]").unwrap();
681
682 Ok(())
683 }
684}
685
686pub type Dictionary = HashMap<String, RailDef<'static>>;
687
688pub fn dictionary_of<Entries>(entries: Entries) -> Dictionary
689where
690 Entries: IntoIterator<Item = RailDef<'static>>,
691{
692 let entries = entries.into_iter().map(|def| (def.name.clone(), def));
693 HashMap::from_iter(entries)
694}
695
696pub type Stab = HashMap<String, RailVal>;
697
698pub fn new_stab() -> Stab {
699 HashMap::new()
700}
701
702#[derive(Clone)]
703pub struct RailDef<'a> {
704 pub name: String,
705 pub description: String,
706 consumes: &'a [RailType],
707 produces: &'a [RailType],
708 action: RailAction<'a>,
709}
710
711#[derive(Clone)]
712pub enum RailAction<'a> {
713 Builtin(Arc<dyn Fn(RailState) -> RailRunResult + 'a>),
714 BuiltinSafe(Arc<dyn Fn(RailState) -> RailState + 'a>),
715 Quotation(RailState),
716}
717
718impl<'a> RailDef<'a> {
719 pub fn on_state<F>(
720 name: &str,
721 description: &str,
722 consumes: &'a [RailType],
723 produces: &'a [RailType],
724 state_action: F,
725 ) -> RailDef<'a>
726 where
727 F: Fn(RailState) -> RailRunResult + 'a,
728 {
729 RailDef {
730 name: name.to_string(),
731 description: description.to_string(),
732 consumes,
733 produces,
734 action: RailAction::Builtin(Arc::new(state_action)),
735 }
736 }
737
738 pub fn on_state_noerr<F>(
740 name: &str,
741 description: &str,
742 consumes: &'a [RailType],
743 produces: &'a [RailType],
744 state_action: F,
745 ) -> RailDef<'a>
746 where
747 F: Fn(RailState) -> RailState + 'a,
748 {
749 RailDef {
750 name: name.to_string(),
751 description: description.to_string(),
752 consumes,
753 produces,
754 action: RailAction::BuiltinSafe(Arc::new(state_action)),
755 }
756 }
757
758 pub fn on_jailed_state<F>(
759 name: &str,
760 description: &str,
761 consumes: &'a [RailType],
762 produces: &'a [RailType],
763 state_action: F,
764 ) -> RailDef<'a>
765 where
766 F: Fn(RailState) -> RailRunResult + 'a,
767 {
768 RailDef {
769 name: name.to_string(),
770 description: description.to_string(),
771 consumes,
772 produces,
773 action: RailAction::Builtin(Arc::new(move |state| {
774 let definitions = state.definitions.clone();
775 let substate = state_action(state)?;
776 Ok(substate.replace_definitions(definitions))
777 })),
778 }
779 }
780
781 pub fn contextless<F>(
782 name: &str,
783 description: &str,
784 consumes: &'a [RailType],
785 produces: &'a [RailType],
786 contextless_action: F,
787 ) -> RailDef<'a>
788 where
789 F: Fn() + 'a,
790 {
791 RailDef::on_state(name, description, consumes, produces, move |state| {
792 contextless_action();
793 Ok(state)
794 })
795 }
796
797 pub fn from_quote(name: &str, description: &str, quote: RailState) -> RailDef<'a> {
798 RailDef {
800 name: name.to_string(),
801 description: description.to_string(),
802 consumes: &[],
803 produces: &[],
804 action: RailAction::Quotation(quote),
805 }
806 }
807
808 pub fn act(self, state: RailState) -> RailRunResult {
809 if state.stack.len() < self.consumes.len() {
810 return Err((
812 state.clone(),
813 RailError::StackUnderflow(state, self.name, self.consumes.to_vec()),
814 ));
815 }
816
817 match self.action {
820 RailAction::Builtin(action) => action(state),
821 RailAction::BuiltinSafe(action) => Ok(action(state)),
822 RailAction::Quotation(quote) => quote.run_in_state(state),
823 }
824 }
825
826 pub fn rename<F>(self, f: F) -> RailDef<'a>
827 where
828 F: Fn(String) -> String,
829 {
830 RailDef {
831 name: f(self.name),
832 description: self.description,
833 consumes: self.consumes,
834 produces: self.produces,
835 action: self.action,
836 }
837 }
838
839 pub fn redescribe<F>(self, f: F) -> RailDef<'a>
840 where
841 F: Fn(String) -> String,
842 {
843 RailDef {
844 name: self.name,
845 description: f(self.description),
846 consumes: self.consumes,
847 produces: self.produces,
848 action: self.action,
849 }
850 }
851}