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>>;