Skip to main content

snarkvm_synthesizer_program/logic/command/
mod.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16mod await_;
17pub use await_::*;
18
19mod branch;
20pub use branch::*;
21
22mod contains;
23pub use contains::*;
24
25mod get;
26pub use get::*;
27
28mod get_or_use;
29pub use get_or_use::*;
30
31mod rand_chacha;
32pub use crate::command::rand_chacha::*;
33
34mod remove;
35pub use remove::*;
36
37mod position;
38pub use position::*;
39
40mod set;
41pub use set::*;
42
43use crate::{
44    CastType,
45    FinalizeOperation,
46    FinalizeRegistersState,
47    FinalizeStoreTrait,
48    Instruction,
49    Operand,
50    StackTrait,
51};
52use console::{
53    network::{error, prelude::*},
54    program::{Identifier, Register},
55};
56use snarkvm_synthesizer_error::FinalizeError;
57
58#[derive(Clone, PartialEq, Eq, Hash)]
59pub enum Command<N: Network> {
60    /// Evaluates the instruction.
61    Instruction(Instruction<N>),
62    /// Awaits the result of a future.
63    Await(Await<N>),
64    /// Returns true if the `key` operand is present in `mapping`, and stores the result into `destination`.
65    Contains(Contains<N>),
66    /// Resolves the `program` and `mapping` operands, returns true if the `key` operand is present in the `mapping`, and stores the result into `destination`.
67    ContainsDynamic(ContainsDynamic<N>),
68    /// Gets the value stored at the `key` operand in `mapping` and stores the result into `destination`.
69    Get(Get<N>),
70    /// Resolves the `program` and `mapping` operands, gets the value stored at the `key` operand in `mapping`, and stores the result into `destination`.
71    GetDynamic(GetDynamic<N>),
72    /// Gets the value stored at the `key` operand in `mapping` and stores the result into `destination`.
73    /// If the key is not present, `default` is stored into `destination`.
74    GetOrUse(GetOrUse<N>),
75    /// Resolves the `program` and `mapping` operands, gets the value stored at the `key` operand in `mapping`, and stores the result into `destination`.
76    /// If the key is not present, `default` is stored into `destination`.
77    GetOrUseDynamic(GetOrUseDynamic<N>),
78    /// Generates a random value using the `rand.chacha` command and stores the result into `destination`.
79    RandChaCha(RandChaCha<N>),
80    /// Removes the (`key`, `value`) entry from the `mapping`.
81    Remove(Remove<N>),
82    /// Sets the value stored at the `key` operand in the `mapping` to `value`.
83    Set(Set<N>),
84    /// Jumps to the `position`, if `first` equals `second`.
85    BranchEq(BranchEq<N>),
86    /// Jumps to the `position`, if `first` does **not** equal `second`.
87    BranchNeq(BranchNeq<N>),
88    /// Indicates a position to which the program can branch to.
89    Position(Position<N>),
90}
91
92impl<N: Network> Command<N> {
93    /// Returns `true` if the command is an async instruction.
94    pub fn is_async(&self) -> bool {
95        matches!(self, Command::Instruction(Instruction::Async(_)))
96    }
97
98    /// Returns `true` if the command is an await command.
99    #[inline]
100    pub fn is_await(&self) -> bool {
101        matches!(self, Command::Await(_))
102    }
103
104    /// Returns `true` if the command is a call instruction.
105    pub fn is_call(&self) -> bool {
106        matches!(self, Command::Instruction(Instruction::Call(_) | Instruction::CallDynamic(_)))
107    }
108
109    /// Returns `true` if the command is specifically a dynamic call instruction.
110    pub fn is_dynamic_call(&self) -> bool {
111        matches!(self, Command::Instruction(Instruction::CallDynamic(_)))
112    }
113
114    /// Returns `true` if the command is a cast-to-record instruction. Covers all three
115    /// record cast variants: static `record`, `external_record`, and `dynamic.record`.
116    pub fn is_cast_to_record(&self) -> bool {
117        matches!(
118            self,
119            Command::Instruction(Instruction::Cast(cast))
120                if matches!(
121                    cast.cast_type(),
122                    CastType::Record(_) | CastType::ExternalRecord(_) | CastType::DynamicRecord
123                )
124        )
125    }
126
127    /// Returns `true` if the command is a `get.record.dynamic` instruction.
128    pub fn is_get_record_dynamic(&self) -> bool {
129        matches!(self, Command::Instruction(Instruction::GetRecordDynamic(_)))
130    }
131
132    /// Returns `true` if the command operates on a record value, either by creating one via
133    /// `cast` (static, external, or dynamic) or by reading one via `get.record.dynamic`.
134    pub fn is_instruction_for_record(&self) -> bool {
135        self.is_cast_to_record() || self.is_get_record_dynamic()
136    }
137
138    /// Returns `true` if the command is a `rand.chacha` command.
139    pub fn is_rand_chacha(&self) -> bool {
140        matches!(self, Command::RandChaCha(_))
141    }
142
143    /// Returns `true` if the command is a write operation.
144    pub fn is_write(&self) -> bool {
145        matches!(self, Command::Set(_) | Command::Remove(_))
146    }
147
148    /// Returns the branch target, if the command is a branch command.
149    /// Otherwise, returns `None`.
150    pub fn branch_to(&self) -> Option<&Identifier<N>> {
151        match self {
152            Command::BranchEq(branch_eq) => Some(branch_eq.position()),
153            Command::BranchNeq(branch_neq) => Some(branch_neq.position()),
154            _ => None,
155        }
156    }
157
158    /// Returns the position name, if the command is a position command.
159    /// Otherwise, returns `None`.
160    pub fn position(&self) -> Option<&Identifier<N>> {
161        match self {
162            Command::Position(position) => Some(position.name()),
163            _ => None,
164        }
165    }
166
167    /// Returns the destination registers of the command.
168    pub fn destinations(&self) -> Vec<Register<N>> {
169        match self {
170            Command::Instruction(instruction) => instruction.destinations(),
171            Command::Contains(contains) => vec![contains.destination().clone()],
172            Command::ContainsDynamic(contains) => vec![contains.destination().clone()],
173            Command::Get(get) => vec![get.destination().clone()],
174            Command::GetDynamic(get) => vec![get.destination().clone()],
175            Command::GetOrUse(get_or_use) => vec![get_or_use.destination().clone()],
176            Command::GetOrUseDynamic(get_or_use) => vec![get_or_use.destination().clone()],
177            Command::RandChaCha(rand_chacha) => vec![rand_chacha.destination().clone()],
178            Command::Await(_)
179            | Command::BranchEq(_)
180            | Command::BranchNeq(_)
181            | Command::Position(_)
182            | Command::Remove(_)
183            | Command::Set(_) => vec![],
184        }
185    }
186
187    /// Returns the operands of the command.
188    #[inline]
189    pub fn operands(&self) -> &[Operand<N>] {
190        match self {
191            Command::Instruction(c) => c.operands(),
192            Command::Await(c) => c.operands(),
193            Command::Contains(c) => c.operands(),
194            Command::ContainsDynamic(c) => c.operands(),
195            Command::Get(c) => c.operands(),
196            Command::GetDynamic(c) => c.operands(),
197            Command::GetOrUse(c) => c.operands(),
198            Command::GetOrUseDynamic(c) => c.operands(),
199            Command::RandChaCha(c) => c.operands(),
200            Command::Remove(c) => c.operands(),
201            Command::Set(c) => c.operands(),
202            Command::BranchEq(c) => c.operands(),
203            Command::BranchNeq(c) => c.operands(),
204            Command::Position(_) => Default::default(),
205        }
206    }
207
208    /// Finalizes the command.
209    pub fn finalize(
210        &self,
211        stack: &impl StackTrait<N>,
212        store: &dyn FinalizeStoreTrait<N>,
213        registers: &mut impl FinalizeRegistersState<N>,
214    ) -> Result<Option<FinalizeOperation<N>>, FinalizeError> {
215        match self {
216            // Finalize the instruction, and return no finalize operation.
217            Command::Instruction(instruction) => instruction.finalize(stack, Some(store), registers).map(|_| None),
218            // `await` commands are processed by the caller of this method.
219            Command::Await(_) => Err(FinalizeError::Anyhow(anyhow!("`await` commands cannot be finalized directly."))),
220            // Finalize the 'contains' command, and return no finalize operation.
221            Command::Contains(contains) => contains.finalize(stack, store, registers).map(|_| None).map_err(Into::into),
222            // Finalize the `contains.dynamic` command, and return no finalize operation.
223            Command::ContainsDynamic(contains_dynamic) => {
224                contains_dynamic.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
225            }
226            // Finalize the 'get' command, and return no finalize operation.
227            Command::Get(get) => get.finalize(stack, store, registers).map(|_| None).map_err(Into::into),
228            // Finalize the `get.dynamic` and return no finalize operation.
229            Command::GetDynamic(get_dynamic) => {
230                get_dynamic.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
231            }
232            // Finalize the 'get.or_use' command, and return no finalize operation.
233            Command::GetOrUse(get_or_use) => {
234                get_or_use.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
235            }
236            // Finalize the `get.or_use.dynamic` command, and return no finalize operation.
237            Command::GetOrUseDynamic(get_or_use_dynamic) => {
238                get_or_use_dynamic.finalize(stack, store, registers).map(|_| None).map_err(Into::into)
239            }
240            // Finalize the `rand.chacha` command, and return no finalize operation.
241            Command::RandChaCha(rand_chacha) => {
242                rand_chacha.finalize(stack, registers).map(|_| None).map_err(Into::into)
243            }
244            // Finalize the 'remove' command, and return the finalize operation.
245            Command::Remove(remove) => remove.finalize(stack, store, registers).map_err(Into::into),
246            // Finalize the 'set' command, and return the finalize operation.
247            Command::Set(set) => set.finalize(stack, store, registers).map(Some).map_err(Into::into),
248            // 'branch.eq' and 'branch.neq' commands are processed by the caller of this method.
249            Command::BranchEq(_) | Command::BranchNeq(_) => {
250                Err(FinalizeError::Anyhow(anyhow!("`branch` commands cannot be finalized directly.")))
251            }
252            // Finalize the `position` command, and return no finalize operation.
253            Command::Position(position) => position.finalize().map(|_| None).map_err(Into::into),
254        }
255    }
256
257    /// Returns whether this commands refers to an external struct.
258    pub fn contains_external_struct(&self) -> bool {
259        match self {
260            Command::Instruction(c) => c.contains_external_struct(),
261            Command::Await(c) => c.contains_external_struct(),
262            Command::Contains(c) => c.contains_external_struct(),
263            // `contains.dynamic` always produces a boolean result and has no type fields that could reference external structs.
264            Command::ContainsDynamic(_) => false,
265            Command::Get(c) => c.contains_external_struct(),
266            Command::GetDynamic(c) => c.destination_type().contains_external_struct(),
267            Command::GetOrUse(c) => c.contains_external_struct(),
268            Command::GetOrUseDynamic(c) => c.destination_type().contains_external_struct(),
269            Command::RandChaCha(c) => c.contains_external_struct(),
270            Command::Remove(c) => c.contains_external_struct(),
271            Command::Set(c) => c.contains_external_struct(),
272            Command::BranchEq(c) => c.contains_external_struct(),
273            Command::BranchNeq(c) => c.contains_external_struct(),
274            Command::Position(c) => c.contains_external_struct(),
275        }
276    }
277
278    /// Returns `true` if the command contains a string type.
279    pub fn contains_string_type(&self) -> bool {
280        self.operands().iter().any(|operand| operand.contains_string_type())
281    }
282
283    /// Returns `true` if the command contains an identifier type in its cast type.
284    pub fn contains_identifier_type(&self) -> Result<bool> {
285        match self {
286            Command::Instruction(instruction) => instruction.contains_identifier_type(),
287            _ => Ok(false),
288        }
289    }
290
291    /// Returns `true` if the command contains an array type with a size that exceeds the given maximum.
292    pub fn exceeds_max_array_size(&self, max_array_size: u32) -> bool {
293        match self {
294            Command::Instruction(instruction) => instruction.exceeds_max_array_size(max_array_size),
295            _ => false,
296        }
297    }
298}
299
300impl<N: Network> FromBytes for Command<N> {
301    /// Reads the command from a buffer.
302    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
303        // Read the variant.
304        let variant = u8::read_le(&mut reader)?;
305        match variant {
306            // Read the instruction.
307            0 => Ok(Self::Instruction(Instruction::read_le(&mut reader)?)),
308            // Read the `await` operation.
309            1 => Ok(Self::Await(Await::read_le(&mut reader)?)),
310            // Read the `contains` operation.
311            2 => Ok(Self::Contains(Contains::read_le(&mut reader)?)),
312            // Read the `get` operation.
313            3 => Ok(Self::Get(Get::read_le(&mut reader)?)),
314            // Read the `get.or_use` operation.
315            4 => Ok(Self::GetOrUse(GetOrUse::read_le(&mut reader)?)),
316            // Read the `rand.chacha` operation.
317            5 => Ok(Self::RandChaCha(RandChaCha::read_le(&mut reader)?)),
318            // Read the `remove` operation.
319            6 => Ok(Self::Remove(Remove::read_le(&mut reader)?)),
320            // Read the `set` operation.
321            7 => Ok(Self::Set(Set::read_le(&mut reader)?)),
322            // Read the `branch.eq` command.
323            8 => Ok(Self::BranchEq(BranchEq::read_le(&mut reader)?)),
324            // Read the `branch.neq` command.
325            9 => Ok(Self::BranchNeq(BranchNeq::read_le(&mut reader)?)),
326            // Read the `position` command.
327            10 => Ok(Self::Position(Position::read_le(&mut reader)?)),
328            // Read the `contains.dynamic` command.
329            11 => Ok(Self::ContainsDynamic(ContainsDynamic::read_le(&mut reader)?)),
330            // Read the `get.dynamic` command.
331            12 => Ok(Self::GetDynamic(GetDynamic::read_le(&mut reader)?)),
332            // Read the `get.or_use.dynamic` command.
333            13 => Ok(Self::GetOrUseDynamic(GetOrUseDynamic::read_le(&mut reader)?)),
334            // Invalid variant.
335            14.. => Err(error(format!("Invalid command variant: {variant}"))),
336        }
337    }
338}
339
340impl<N: Network> ToBytes for Command<N> {
341    /// Writes the command to a buffer.
342    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
343        match self {
344            Self::Instruction(instruction) => {
345                // Write the variant.
346                0u8.write_le(&mut writer)?;
347                // Write the instruction.
348                instruction.write_le(&mut writer)
349            }
350            Self::Await(await_) => {
351                // Write the variant.
352                1u8.write_le(&mut writer)?;
353                // Write the `await` operation.
354                await_.write_le(&mut writer)
355            }
356            Self::Contains(contains) => {
357                // Write the variant.
358                2u8.write_le(&mut writer)?;
359                // Write the `contains` operation.
360                contains.write_le(&mut writer)
361            }
362            Self::Get(get) => {
363                // Write the variant.
364                3u8.write_le(&mut writer)?;
365                // Write the `get` operation.
366                get.write_le(&mut writer)
367            }
368            Self::GetOrUse(get_or_use) => {
369                // Write the variant.
370                4u8.write_le(&mut writer)?;
371                // Write the defaulting `get` operation.
372                get_or_use.write_le(&mut writer)
373            }
374            Self::RandChaCha(rand_chacha) => {
375                // Write the variant.
376                5u8.write_le(&mut writer)?;
377                // Write the `rand.chacha` operation.
378                rand_chacha.write_le(&mut writer)
379            }
380            Self::Remove(remove) => {
381                // Write the variant.
382                6u8.write_le(&mut writer)?;
383                // Write the remove.
384                remove.write_le(&mut writer)
385            }
386            Self::Set(set) => {
387                // Write the variant.
388                7u8.write_le(&mut writer)?;
389                // Write the set.
390                set.write_le(&mut writer)
391            }
392            Self::BranchEq(branch_eq) => {
393                // Write the variant.
394                8u8.write_le(&mut writer)?;
395                // Write the `branch.eq` command.
396                branch_eq.write_le(&mut writer)
397            }
398            Self::BranchNeq(branch_neq) => {
399                // Write the variant.
400                9u8.write_le(&mut writer)?;
401                // Write the `branch.neq` command.
402                branch_neq.write_le(&mut writer)
403            }
404            Self::Position(position) => {
405                // Write the variant.
406                10u8.write_le(&mut writer)?;
407                // Write the position command.
408                position.write_le(&mut writer)
409            }
410            Self::ContainsDynamic(contains_dynamic) => {
411                // Write the variant.
412                11u8.write_le(&mut writer)?;
413                // Write the `contains.dynamic` command.
414                contains_dynamic.write_le(&mut writer)
415            }
416            Self::GetDynamic(get_dynamic) => {
417                // Write the variant.
418                12u8.write_le(&mut writer)?;
419                // Write the `get.dynamic` command.
420                get_dynamic.write_le(&mut writer)
421            }
422            Self::GetOrUseDynamic(get_or_use_dynamic) => {
423                // Write the variant.
424                13u8.write_le(&mut writer)?;
425                // Write the `get.or_use.dynamic` command.
426                get_or_use_dynamic.write_le(&mut writer)
427            }
428        }
429    }
430}
431
432impl<N: Network> Parser for Command<N> {
433    /// Parses the string into the command.
434    #[inline]
435    fn parse(string: &str) -> ParserResult<Self> {
436        // Parse the command.
437        // Note that the order of the parsers is important.
438        alt((
439            map(Await::parse, |await_| Self::Await(await_)),
440            map(ContainsDynamic::parse, |contains_dynamic| Self::ContainsDynamic(contains_dynamic)),
441            map(Contains::parse, |contains| Self::Contains(contains)),
442            map(GetOrUseDynamic::parse, |get_or_use_dynamic| Self::GetOrUseDynamic(get_or_use_dynamic)),
443            map(GetOrUse::parse, |get_or_use| Self::GetOrUse(get_or_use)),
444            map(GetDynamic::parse, |get_dynamic| Self::GetDynamic(get_dynamic)),
445            map(Get::parse, |get| Self::Get(get)),
446            map(RandChaCha::parse, |rand_chacha| Self::RandChaCha(rand_chacha)),
447            map(Remove::parse, |remove| Self::Remove(remove)),
448            map(Set::parse, |set| Self::Set(set)),
449            map(BranchEq::parse, |branch_eq| Self::BranchEq(branch_eq)),
450            map(BranchNeq::parse, |branch_neq| Self::BranchNeq(branch_neq)),
451            map(Position::parse, |position| Self::Position(position)),
452            map(Instruction::parse, |instruction| Self::Instruction(instruction)),
453        ))(string)
454    }
455}
456
457impl<N: Network> FromStr for Command<N> {
458    type Err = Error;
459
460    /// Parses the string into the command.
461    #[inline]
462    fn from_str(string: &str) -> Result<Self> {
463        match Self::parse(string) {
464            Ok((remainder, object)) => {
465                // Ensure the remainder is empty.
466                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
467                // Return the object.
468                Ok(object)
469            }
470            Err(error) => bail!("Failed to parse string. {error}"),
471        }
472    }
473}
474
475impl<N: Network> Debug for Command<N> {
476    /// Prints the command as a string.
477    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
478        Display::fmt(self, f)
479    }
480}
481
482impl<N: Network> Display for Command<N> {
483    /// Prints the command as a string.
484    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
485        match self {
486            Self::Instruction(instruction) => Display::fmt(instruction, f),
487            Self::Await(await_) => Display::fmt(await_, f),
488            Self::Contains(contains) => Display::fmt(contains, f),
489            Self::ContainsDynamic(contains_dynamic) => Display::fmt(contains_dynamic, f),
490            Self::Get(get) => Display::fmt(get, f),
491            Self::GetDynamic(get_dynamic) => Display::fmt(get_dynamic, f),
492            Self::GetOrUse(get_or_use) => Display::fmt(get_or_use, f),
493            Self::GetOrUseDynamic(get_or_use_dynamic) => Display::fmt(get_or_use_dynamic, f),
494            Self::RandChaCha(rand_chacha) => Display::fmt(rand_chacha, f),
495            Self::Remove(remove) => Display::fmt(remove, f),
496            Self::Set(set) => Display::fmt(set, f),
497            Self::BranchEq(branch_eq) => Display::fmt(branch_eq, f),
498            Self::BranchNeq(branch_neq) => Display::fmt(branch_neq, f),
499            Self::Position(position) => Display::fmt(position, f),
500        }
501    }
502}
503
504#[cfg(test)]
505mod tests {
506    use super::*;
507    use console::network::MainnetV0;
508
509    type CurrentNetwork = MainnetV0;
510
511    #[test]
512    fn test_command_bytes() {
513        // Decrement
514        let expected = "decrement object[r0] by r1;";
515        Command::<CurrentNetwork>::parse(expected).unwrap_err();
516
517        // Instruction
518        let expected = "add r0 r1 into r2;";
519        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
520        let bytes = command.to_bytes_le().unwrap();
521        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
522
523        // Increment
524        let expected = "increment object[r0] by r1;";
525        Command::<CurrentNetwork>::parse(expected).unwrap_err();
526
527        // Await
528        let expected = "await r1;";
529        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
530        let bytes = command.to_bytes_le().unwrap();
531        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
532
533        // Contains
534        let expected = "contains object[r0] into r1;";
535        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
536        let bytes = command.to_bytes_le().unwrap();
537        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
538
539        // ContainsDynamic
540        let expected = "contains.dynamic r0 r1 r2[r3] into r4;";
541        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
542        let bytes = command.to_bytes_le().unwrap();
543        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
544
545        // Get
546        let expected = "get object[r0] into r1;";
547        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
548        let bytes = command.to_bytes_le().unwrap();
549        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
550
551        // GetDynamic
552        let expected = "get.dynamic r0 r1 r2[r3] into r4 as field;";
553        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
554        let bytes = command.to_bytes_le().unwrap();
555        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
556
557        // GetOr
558        let expected = "get.or_use object[r0] r1 into r2;";
559        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
560        let bytes = command.to_bytes_le().unwrap();
561        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
562
563        // GetOrDynamic
564        let expected = "get.or_use.dynamic r0 r1 r2[r3] r4 into r5 as credits;";
565        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
566        let bytes = command.to_bytes_le().unwrap();
567        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
568
569        // RandChaCha
570        let expected = "rand.chacha into r1 as field;";
571        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
572        let bytes = command.to_bytes_le().unwrap();
573        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
574
575        // RandChaCha
576        let expected = "rand.chacha r0 r1 into r2 as group;";
577        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
578        let bytes = command.to_bytes_le().unwrap();
579        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
580
581        // Remove
582        let expected = "remove object[r0];";
583        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
584        let bytes = command.to_bytes_le().unwrap();
585        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
586
587        // Set
588        let expected = "set r0 into object[r1];";
589        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
590        let bytes = command.to_bytes_le().unwrap();
591        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
592
593        // BranchEq
594        let expected = "branch.eq r0 r1 to exit;";
595        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
596        let bytes = command.to_bytes_le().unwrap();
597        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
598
599        // BranchNeq
600        let expected = "branch.neq r2 r3 to start;";
601        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
602        let bytes = command.to_bytes_le().unwrap();
603        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
604
605        // Position
606        let expected = "position exit;";
607        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
608        let bytes = command.to_bytes_le().unwrap();
609        assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
610    }
611
612    #[test]
613    fn test_command_parse() {
614        // Decrement
615        let expected = "decrement object[r0] by r1;";
616        Command::<CurrentNetwork>::parse(expected).unwrap_err();
617
618        // Instruction
619        let expected = "add r0 r1 into r2;";
620        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
621        assert_eq!(Command::Instruction(Instruction::from_str(expected).unwrap()), command);
622        assert_eq!(expected, command.to_string());
623
624        // Increment
625        let expected = "increment object[r0] by r1;";
626        Command::<CurrentNetwork>::parse(expected).unwrap_err();
627
628        // Contains
629        let expected = "contains object[r0] into r1;";
630        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
631        assert_eq!(Command::Contains(Contains::from_str(expected).unwrap()), command);
632        assert_eq!(expected, command.to_string());
633
634        // ContainsDynamic
635        let expected = "contains.dynamic r0 r1 r2[r3] into r4;";
636        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
637        assert_eq!(Command::ContainsDynamic(ContainsDynamic::from_str(expected).unwrap()), command);
638        assert_eq!(expected, command.to_string());
639
640        // Get
641        let expected = "get object[r0] into r1;";
642        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
643        assert_eq!(Command::Get(Get::from_str(expected).unwrap()), command);
644        assert_eq!(expected, command.to_string());
645
646        // GetDynamic
647        let expected = "get.dynamic r0 r1 r2[r3] into r4 as u8;";
648        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
649        assert_eq!(Command::GetDynamic(GetDynamic::from_str(expected).unwrap()), command);
650        assert_eq!(expected, command.to_string());
651
652        // GetOr
653        let expected = "get.or_use object[r0] r1 into r2;";
654        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
655        assert_eq!(Command::GetOrUse(GetOrUse::from_str(expected).unwrap()), command);
656        assert_eq!(expected, command.to_string());
657
658        // GetOrDynamic
659        let expected = "get.or_use.dynamic r0 r1 r2[r3] r4 into r5 as Foo;";
660        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
661        assert_eq!(Command::GetOrUseDynamic(GetOrUseDynamic::from_str(expected).unwrap()), command);
662        assert_eq!(expected, command.to_string());
663
664        // RandChaCha
665        let expected = "rand.chacha into r1 as field;";
666        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
667        assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
668        assert_eq!(expected, command.to_string());
669
670        // RandChaCha
671        let expected = "rand.chacha r0 r1 into r2 as group;";
672        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
673        assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
674        assert_eq!(expected, command.to_string());
675
676        // Remove
677        let expected = "remove object[r0];";
678        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
679        assert_eq!(Command::Remove(Remove::from_str(expected).unwrap()), command);
680        assert_eq!(expected, command.to_string());
681
682        // Set
683        let expected = "set r0 into object[r1];";
684        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
685        assert_eq!(Command::Set(Set::from_str(expected).unwrap()), command);
686        assert_eq!(expected, command.to_string());
687
688        // BranchEq
689        let expected = "branch.eq r0 r1 to exit;";
690        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
691        assert_eq!(Command::BranchEq(BranchEq::from_str(expected).unwrap()), command);
692        assert_eq!(expected, command.to_string());
693
694        // BranchNeq
695        let expected = "branch.neq r2 r3 to start;";
696        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
697        assert_eq!(Command::BranchNeq(BranchNeq::from_str(expected).unwrap()), command);
698        assert_eq!(expected, command.to_string());
699
700        // Position
701        let expected = "position exit;";
702        let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
703        assert_eq!(Command::Position(Position::from_str(expected).unwrap()), command);
704        assert_eq!(expected, command.to_string());
705    }
706}