Skip to main content

just_engine/runner/eval/
types.rs

1//! Core types for the evaluation engine.
2
3use crate::runner::ds::error::JErrorType;
4use crate::runner::ds::value::JsValue;
5
6/// Completion record type.
7/// Represents the result of evaluating a statement or expression.
8#[derive(Debug, Clone, PartialEq)]
9pub enum CompletionType {
10    /// Normal completion - execution continues.
11    Normal,
12    /// Return completion - function returns.
13    Return,
14    /// Throw completion - exception thrown.
15    Throw,
16    /// Break completion - break from loop/switch.
17    Break,
18    /// Continue completion - continue loop iteration.
19    Continue,
20    /// Yield completion - generator yields a value.
21    Yield,
22}
23
24/// Completion record.
25/// Every statement evaluation returns a completion record.
26pub struct Completion {
27    /// The type of completion.
28    pub completion_type: CompletionType,
29    /// The value, if any.
30    pub value: Option<JsValue>,
31    /// Target label for break/continue.
32    pub target: Option<String>,
33}
34
35impl Completion {
36    /// Create a normal completion with no value.
37    pub fn normal() -> Self {
38        Completion {
39            completion_type: CompletionType::Normal,
40            value: None,
41            target: None,
42        }
43    }
44
45    /// Create a normal completion with a value.
46    pub fn normal_with_value(value: JsValue) -> Self {
47        Completion {
48            completion_type: CompletionType::Normal,
49            value: Some(value),
50            target: None,
51        }
52    }
53
54    /// Create a return completion.
55    pub fn return_value(value: JsValue) -> Self {
56        Completion {
57            completion_type: CompletionType::Return,
58            value: Some(value),
59            target: None,
60        }
61    }
62
63    /// Create a return completion with undefined.
64    pub fn return_undefined() -> Self {
65        Completion {
66            completion_type: CompletionType::Return,
67            value: Some(JsValue::Undefined),
68            target: None,
69        }
70    }
71
72    /// Create a throw completion (exception).
73    pub fn throw(error: JErrorType) -> Self {
74        Completion {
75            completion_type: CompletionType::Throw,
76            value: Some(JsValue::String(error.to_string())),
77            target: None,
78        }
79    }
80
81    /// Create a break completion.
82    pub fn break_completion(target: Option<String>) -> Self {
83        Completion {
84            completion_type: CompletionType::Break,
85            value: None,
86            target,
87        }
88    }
89
90    /// Create a continue completion.
91    pub fn continue_completion(target: Option<String>) -> Self {
92        Completion {
93            completion_type: CompletionType::Continue,
94            value: None,
95            target,
96        }
97    }
98
99    /// Create a yield completion with a value.
100    pub fn yield_value(value: JsValue) -> Self {
101        Completion {
102            completion_type: CompletionType::Yield,
103            value: Some(value),
104            target: None,
105        }
106    }
107
108    /// Check if this is a normal completion.
109    pub fn is_normal(&self) -> bool {
110        matches!(self.completion_type, CompletionType::Normal)
111    }
112
113    /// Check if this is an abrupt completion (not normal).
114    pub fn is_abrupt(&self) -> bool {
115        !self.is_normal()
116    }
117
118    /// Get the value, or undefined if none.
119    pub fn get_value(&self) -> JsValue {
120        self.value.clone().unwrap_or(JsValue::Undefined)
121    }
122
123    /// Update the value of a normal completion.
124    pub fn update_empty(self, value: JsValue) -> Self {
125        if self.is_normal() && self.value.is_none() {
126            Completion {
127                value: Some(value),
128                ..self
129            }
130        } else {
131            self
132        }
133    }
134}
135
136/// Reference base type.
137/// A reference can be based on an object, environment record, or be unresolvable.
138#[derive(Clone)]
139pub enum ReferenceBase {
140    /// Reference to a property on an object.
141    Object(JsValue),
142    /// Reference to a binding in an environment record.
143    Environment(EnvironmentRef),
144    /// Unresolvable reference (identifier not found).
145    Unresolvable,
146}
147
148/// Reference to an environment record.
149#[derive(Clone)]
150pub struct EnvironmentRef {
151    // Will be expanded to actual environment record reference
152    pub name: String,
153}
154
155/// Reference type.
156/// Used for identifier resolution and property access.
157#[derive(Clone)]
158pub struct Reference {
159    /// The base value (object or environment).
160    pub base: ReferenceBase,
161    /// The referenced name (property name or identifier).
162    pub referenced_name: String,
163    /// Whether this is a strict mode reference.
164    pub strict: bool,
165    /// The `this` value for super references.
166    pub this_value: Option<JsValue>,
167}
168
169impl Reference {
170    /// Create a new reference to a property on an object.
171    pub fn property(base: JsValue, name: impl Into<String>, strict: bool) -> Self {
172        Reference {
173            base: ReferenceBase::Object(base),
174            referenced_name: name.into(),
175            strict,
176            this_value: None,
177        }
178    }
179
180    /// Create a new reference to an environment binding.
181    pub fn environment(env_name: impl Into<String>, binding_name: impl Into<String>, strict: bool) -> Self {
182        Reference {
183            base: ReferenceBase::Environment(EnvironmentRef { name: env_name.into() }),
184            referenced_name: binding_name.into(),
185            strict,
186            this_value: None,
187        }
188    }
189
190    /// Create an unresolvable reference.
191    pub fn unresolvable(name: impl Into<String>, strict: bool) -> Self {
192        Reference {
193            base: ReferenceBase::Unresolvable,
194            referenced_name: name.into(),
195            strict,
196            this_value: None,
197        }
198    }
199
200    /// Check if this reference has a primitive base.
201    pub fn has_primitive_base(&self) -> bool {
202        match &self.base {
203            ReferenceBase::Object(v) => matches!(v, JsValue::Boolean(_) | JsValue::String(_) | JsValue::Number(_)),
204            _ => false,
205        }
206    }
207
208    /// Check if this is a property reference.
209    pub fn is_property_reference(&self) -> bool {
210        matches!(self.base, ReferenceBase::Object(_)) || self.has_primitive_base()
211    }
212
213    /// Check if this reference is unresolvable.
214    pub fn is_unresolvable(&self) -> bool {
215        matches!(self.base, ReferenceBase::Unresolvable)
216    }
217
218    /// Check if this is a super reference.
219    pub fn is_super_reference(&self) -> bool {
220        self.this_value.is_some()
221    }
222
223    /// Get the base object value.
224    pub fn get_base(&self) -> Option<&JsValue> {
225        match &self.base {
226            ReferenceBase::Object(v) => Some(v),
227            _ => None,
228        }
229    }
230
231    /// Get the this value for method calls.
232    pub fn get_this_value(&self) -> JsValue {
233        if let Some(ref this) = self.this_value {
234            this.clone()
235        } else if let ReferenceBase::Object(ref base) = self.base {
236            base.clone()
237        } else {
238            JsValue::Undefined
239        }
240    }
241}
242
243/// Result type for evaluation operations.
244pub type EvalResult = Result<Completion, JErrorType>;
245
246/// Result type for value-returning operations.
247pub type ValueResult = Result<JsValue, JErrorType>;
248
249/// Result type for reference-returning operations.
250pub type ReferenceResult = Result<Reference, JErrorType>;