arithmetic_eval/exec/
command.rs

1//! Executable `Command` and its building blocks.
2
3use arithmetic_parser::{BinaryOp, Location, LvalueLen, UnaryOp};
4
5use crate::alloc::{String, Vec};
6
7/// Pointer to a register or constant.
8#[derive(Debug)]
9pub(crate) enum Atom<T> {
10    Constant(T),
11    Register(usize),
12    Void,
13}
14
15impl<T: Clone> Clone for Atom<T> {
16    fn clone(&self) -> Self {
17        match self {
18            Self::Constant(literal) => Self::Constant(literal.clone()),
19            Self::Register(index) => Self::Register(*index),
20            Self::Void => Self::Void,
21        }
22    }
23}
24
25pub(crate) type LocatedAtom<T> = Location<Atom<T>>;
26
27#[derive(Debug, Clone)]
28pub(crate) enum FieldName {
29    Index(usize),
30    Name(String),
31}
32
33/// Atomic operation on registers and/or constants.
34#[derive(Debug, Clone)]
35pub(crate) enum CompiledExpr<T> {
36    Atom(Atom<T>),
37    Tuple(Vec<Atom<T>>),
38    Object(Vec<(String, Atom<T>)>),
39    Unary {
40        op: UnaryOp,
41        inner: LocatedAtom<T>,
42    },
43    Binary {
44        op: BinaryOp,
45        lhs: LocatedAtom<T>,
46        rhs: LocatedAtom<T>,
47    },
48    FieldAccess {
49        receiver: LocatedAtom<T>,
50        field: FieldName,
51    },
52    FunctionCall {
53        name: LocatedAtom<T>,
54        // Original function name if it is a proper variable name.
55        original_name: Option<String>,
56        args: Vec<LocatedAtom<T>>,
57    },
58    DefineFunction {
59        ptr: usize,
60        captures: Vec<LocatedAtom<T>>,
61        // Original capture names.
62        capture_names: Vec<String>,
63    },
64}
65
66/// Commands for a primitive register VM used to execute compiled programs.
67#[derive(Debug, Clone)]
68pub(crate) enum Command<T> {
69    /// Create a new register and push the result of the specified computation there.
70    Push(CompiledExpr<T>),
71
72    /// Destructure a tuple value. This will push `start_len` starting elements from the tuple,
73    /// the middle of the tuple (as a tuple), and `end_len` ending elements from the tuple
74    /// as new registers, in this order.
75    Destructure {
76        /// Index of the register with the value.
77        source: usize,
78        /// Number of starting arguments to place in separate registers.
79        start_len: usize,
80        /// Number of ending arguments to place in separate registers.
81        end_len: usize,
82        /// Acceptable length(s) of the source.
83        lvalue_len: LvalueLen,
84        /// Does `lvalue_len` should be checked? When destructuring arguments for functions,
85        /// this check was performed previously.
86        unchecked: bool,
87    },
88
89    /// Copies the source register into the destination. The destination register must exist.
90    Copy { source: usize, destination: usize },
91
92    /// Annotates a register as containing the specified variable.
93    Annotate { register: usize, name: String },
94
95    /// Signals that the following commands are executed in the inner scope.
96    StartInnerScope,
97    /// Signals that the following commands are executed in the global scope.
98    EndInnerScope,
99    /// Signals to truncate registers to the specified number.
100    TruncateRegisters(usize),
101}
102
103pub(crate) type LocatedCommand<T> = Location<Command<T>>;