Skip to main content

aranya_policy_module/
instructions.rs

1use core::{
2    fmt::{self, Display},
3    num::NonZeroUsize,
4};
5
6use aranya_policy_ast::Identifier;
7use serde::{Deserialize, Serialize};
8
9mod meta;
10
11pub use meta::*;
12
13use crate::{Label, data::ConstValue};
14
15/// Reason for ending execution.
16#[must_use]
17#[derive(
18    Clone,
19    Debug,
20    Eq,
21    PartialEq,
22    Serialize,
23    Deserialize,
24    rkyv::Archive,
25    rkyv::Deserialize,
26    rkyv::Serialize,
27)]
28pub enum ExitReason {
29    /// Execution completed without errors.
30    Normal,
31    /// Execution is paused to return a result, which is at the top of the stack. Call `RunState::run()` again to resume.
32    Yield,
33    /// Execution was aborted gracefully, due an error.
34    Check,
35    /// Execution was aborted due to an unhandled error.
36    Panic,
37}
38
39impl ExitReason {
40    /// Asserts that the reason is `ExitReason::Normal`.
41    #[cfg(feature = "testing")]
42    pub fn success(self) {
43        assert_eq!(self, Self::Normal);
44    }
45}
46
47impl Display for ExitReason {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        match self {
50            Self::Normal => f.write_str("normal"),
51            Self::Yield => f.write_str("yield"),
52            Self::Check => f.write_str("check"),
53            Self::Panic => f.write_str("panic"),
54        }
55    }
56}
57
58/// The target of a branch
59#[derive(
60    Debug,
61    Clone,
62    Eq,
63    PartialEq,
64    Serialize,
65    Deserialize,
66    rkyv::Archive,
67    rkyv::Deserialize,
68    rkyv::Serialize,
69)]
70pub enum Target {
71    /// An unresolved target with a symbolic name
72    Unresolved(Label),
73    /// A resolved target referring to an address
74    Resolved(usize),
75}
76
77impl Target {
78    /// Get the resolved address or None if it has not been resolved.
79    pub fn resolved(&self) -> Option<usize> {
80        match self {
81            Self::Resolved(i) => Some(*i),
82            Self::Unresolved(_) => None,
83        }
84    }
85}
86
87impl Display for Target {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            Self::Unresolved(label) => write!(f, "<{label}>"),
91            Self::Resolved(addr) => write!(f, "{addr}"),
92        }
93    }
94}
95
96/// Type of `Value` wrapping
97#[derive(
98    Debug,
99    Clone,
100    Copy,
101    Eq,
102    PartialEq,
103    Serialize,
104    Deserialize,
105    rkyv::Archive,
106    rkyv::Deserialize,
107    rkyv::Serialize,
108)]
109pub enum WrapType {
110    /// Wrap in Result::Ok
111    Ok,
112    /// Wrap in Result::Err
113    Err,
114    /// Wrap in Option::Some
115    Some,
116}
117
118impl Display for WrapType {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        match self {
121            Self::Ok => f.write_str("ok"),
122            Self::Err => f.write_str("err"),
123            Self::Some => f.write_str("some"),
124        }
125    }
126}
127
128/// The machine instruction types
129#[derive(
130    Debug,
131    Clone,
132    Eq,
133    PartialEq,
134    Serialize,
135    Deserialize,
136    rkyv::Archive,
137    rkyv::Deserialize,
138    rkyv::Serialize,
139)]
140pub enum Instruction {
141    // data
142    /// Push a value onto the stack
143    Const(ConstValue),
144    /// Push an identifier onto the stack
145    Identifier(Identifier),
146    /// Define a local value by name
147    Def(Identifier),
148    /// Get a local value by name
149    Get(Identifier),
150    /// Duplicate the value at the top of the stack
151    Dup,
152    /// Remove a value from the top of the stack
153    Pop,
154    // control flow
155    /// Define the beginning of a block
156    Block,
157    /// Define the end of a block
158    End,
159    /// Jump forward to the target in the current block
160    Jump(Target),
161    /// Jump if top of stack is true
162    Branch(Target),
163    /// Jump to the beginning of the block
164    Next,
165    /// Jump to the end of the block
166    Last,
167    /// Call regular function at target
168    Call(Target),
169    /// Call external function (FFI), specified by module, procedure indices. The FFI modules should be added to the MachineIO.
170    ExtCall(usize, usize),
171    /// Return to the last address on the control flow stack
172    Return,
173    /// End execution non-fatally
174    Exit(ExitReason),
175    // arithmetic/logic
176    /// Add two numbers
177    Add,
178    /// Subtract two numbers
179    Sub,
180    /// Add two numbers with saturation
181    SaturatingAdd,
182    /// Subtract two numbers with saturation
183    SaturatingSub,
184    /// Logical negation
185    Not,
186    /// Greater than
187    Gt,
188    /// Less than
189    Lt,
190    /// Equality
191    Eq,
192    // facts
193    /// Create a fact object by name
194    FactNew(Identifier),
195    /// Set a key member
196    FactKeySet(Identifier),
197    /// Set a value member
198    FactValueSet(Identifier),
199    // structs
200    /// Create a struct object by name
201    StructNew(Identifier),
202    /// Add a member to the struct
203    StructSet(Identifier),
204    /// Get a member from the struct
205    StructGet(Identifier),
206    /// Add multiple members to the struct
207    MStructSet(NonZeroUsize),
208    /// Get multiple members from the struct
209    MStructGet(NonZeroUsize),
210    /// Cast previous stack value to given type
211    Cast(Identifier),
212    /// Wrap the value on top of the stack in Some, Ok, or Err, depending on wrap type.
213    Wrap(WrapType),
214    /// Check if the value on top of the stack is the given wrap type (pushes bool).
215    Is(WrapType),
216    /// Unwrap the inner value from a Result (Ok or Err). Will eventually support Optional (Some) as well.
217    Unwrap(WrapType),
218    // context-specific
219    /// Publish a struct as a command
220    Publish,
221    /// Create a fact
222    Create,
223    /// Delete a fact
224    Delete,
225    /// Update a fact
226    Update,
227    /// Emit an effect
228    Emit,
229    /// Query for a fact
230    Query,
231    /// Count facts, up to a given limit
232    FactCount(i64),
233    /// Execute a fact query, and retain results so they can be consumed with `QueryNext`.
234    QueryStart,
235    /// Fetches the next result, and pushes it onto the stack
236    QueryNext(Identifier),
237    /// Serialize a command struct
238    Serialize,
239    /// Deserialize a command struct
240    Deserialize,
241    /// Save the stack depth for later restoration.
242    SaveSP,
243    /// Restore the stack depth.
244    RestoreSP,
245    /// Metadata for tracing
246    Meta(Meta),
247}
248
249impl Display for Instruction {
250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251        match self {
252            Self::Const(v) => write!(f, "const {v}"),
253            Self::Identifier(ident) => write!(f, "ident {ident}"),
254            Self::Def(ident) => write!(f, "def {ident}"),
255            Self::Get(ident) => write!(f, "get {ident}"),
256            Self::Dup => write!(f, "dup"),
257            Self::Pop => write!(f, "pop"),
258            Self::Block => write!(f, "block"),
259            Self::End => write!(f, "end"),
260            Self::Jump(t) => write!(f, "jump {t}"),
261            Self::Branch(t) => write!(f, "branch {t}"),
262            Self::Next => write!(f, "next"),
263            Self::Last => write!(f, "last"),
264            Self::Call(t) => write!(f, "call {t}"),
265            Self::ExtCall(module, proc) => write!(f, "extcall {module} {proc}"),
266            Self::Return => write!(f, "return"),
267            Self::Exit(reason) => write!(f, "exit {reason}"),
268            Self::Add => write!(f, "add"),
269            Self::Sub => write!(f, "sub"),
270            Self::SaturatingAdd => write!(f, "saturating_add"),
271            Self::SaturatingSub => write!(f, "saturating_sub"),
272            Self::Not => write!(f, "not"),
273            Self::Gt => write!(f, "gt"),
274            Self::Lt => write!(f, "lt"),
275            Self::Eq => write!(f, "eq"),
276            Self::FactNew(ident) => write!(f, "fact.new {ident}"),
277            Self::FactKeySet(ident) => write!(f, "fact.kset {ident}"),
278            Self::FactValueSet(ident) => write!(f, "fact.vset {ident}"),
279            Self::StructNew(ident) => write!(f, "struct.new {ident}"),
280            Self::StructSet(ident) => write!(f, "struct.set {ident}"),
281            Self::StructGet(ident) => write!(f, "struct.get {ident}"),
282            Self::MStructGet(n) => write!(f, "mstruct.get {n}"),
283            Self::MStructSet(n) => write!(f, "mstruct.set {n}"),
284            Self::Cast(ident) => write!(f, "cast {ident}"),
285            Self::Wrap(wrap_type) => write!(f, "wrap {wrap_type}"),
286            Self::Is(wrap_type) => write!(f, "is {wrap_type}"),
287            Self::Unwrap(wrap_type) => write!(f, "unwrap {wrap_type}"),
288            Self::Publish => write!(f, "publish"),
289            Self::Create => write!(f, "create"),
290            Self::Delete => write!(f, "delete"),
291            Self::Update => write!(f, "update"),
292            Self::Emit => write!(f, "emit"),
293            Self::Query => write!(f, "query"),
294            Self::FactCount(limit) => write!(f, "fact.count {limit}"),
295            Self::QueryStart => write!(f, "query.start"),
296            Self::QueryNext(ident) => write!(f, "query.next {ident}"),
297            Self::Serialize => write!(f, "serialize"),
298            Self::Deserialize => write!(f, "deserialize"),
299            Self::SaveSP => write!(f, "save SP"),
300            Self::RestoreSP => write!(f, "restore SP"),
301            Self::Meta(m) => write!(f, "meta: {m}"),
302        }
303    }
304}