use crate::runner::ds::error::JErrorType;
use crate::runner::ds::value::JsValue;
#[derive(Debug, Clone, PartialEq)]
pub enum CompletionType {
Normal,
Return,
Throw,
Break,
Continue,
Yield,
}
pub struct Completion {
pub completion_type: CompletionType,
pub value: Option<JsValue>,
pub target: Option<String>,
}
impl Completion {
pub fn normal() -> Self {
Completion {
completion_type: CompletionType::Normal,
value: None,
target: None,
}
}
pub fn normal_with_value(value: JsValue) -> Self {
Completion {
completion_type: CompletionType::Normal,
value: Some(value),
target: None,
}
}
pub fn return_value(value: JsValue) -> Self {
Completion {
completion_type: CompletionType::Return,
value: Some(value),
target: None,
}
}
pub fn return_undefined() -> Self {
Completion {
completion_type: CompletionType::Return,
value: Some(JsValue::Undefined),
target: None,
}
}
pub fn throw(error: JErrorType) -> Self {
Completion {
completion_type: CompletionType::Throw,
value: Some(JsValue::String(error.to_string())),
target: None,
}
}
pub fn break_completion(target: Option<String>) -> Self {
Completion {
completion_type: CompletionType::Break,
value: None,
target,
}
}
pub fn continue_completion(target: Option<String>) -> Self {
Completion {
completion_type: CompletionType::Continue,
value: None,
target,
}
}
pub fn yield_value(value: JsValue) -> Self {
Completion {
completion_type: CompletionType::Yield,
value: Some(value),
target: None,
}
}
pub fn is_normal(&self) -> bool {
matches!(self.completion_type, CompletionType::Normal)
}
pub fn is_abrupt(&self) -> bool {
!self.is_normal()
}
pub fn get_value(&self) -> JsValue {
self.value.clone().unwrap_or(JsValue::Undefined)
}
pub fn update_empty(self, value: JsValue) -> Self {
if self.is_normal() && self.value.is_none() {
Completion {
value: Some(value),
..self
}
} else {
self
}
}
}
#[derive(Clone)]
pub enum ReferenceBase {
Object(JsValue),
Environment(EnvironmentRef),
Unresolvable,
}
#[derive(Clone)]
pub struct EnvironmentRef {
pub name: String,
}
#[derive(Clone)]
pub struct Reference {
pub base: ReferenceBase,
pub referenced_name: String,
pub strict: bool,
pub this_value: Option<JsValue>,
}
impl Reference {
pub fn property(base: JsValue, name: impl Into<String>, strict: bool) -> Self {
Reference {
base: ReferenceBase::Object(base),
referenced_name: name.into(),
strict,
this_value: None,
}
}
pub fn environment(env_name: impl Into<String>, binding_name: impl Into<String>, strict: bool) -> Self {
Reference {
base: ReferenceBase::Environment(EnvironmentRef { name: env_name.into() }),
referenced_name: binding_name.into(),
strict,
this_value: None,
}
}
pub fn unresolvable(name: impl Into<String>, strict: bool) -> Self {
Reference {
base: ReferenceBase::Unresolvable,
referenced_name: name.into(),
strict,
this_value: None,
}
}
pub fn has_primitive_base(&self) -> bool {
match &self.base {
ReferenceBase::Object(v) => matches!(v, JsValue::Boolean(_) | JsValue::String(_) | JsValue::Number(_)),
_ => false,
}
}
pub fn is_property_reference(&self) -> bool {
matches!(self.base, ReferenceBase::Object(_)) || self.has_primitive_base()
}
pub fn is_unresolvable(&self) -> bool {
matches!(self.base, ReferenceBase::Unresolvable)
}
pub fn is_super_reference(&self) -> bool {
self.this_value.is_some()
}
pub fn get_base(&self) -> Option<&JsValue> {
match &self.base {
ReferenceBase::Object(v) => Some(v),
_ => None,
}
}
pub fn get_this_value(&self) -> JsValue {
if let Some(ref this) = self.this_value {
this.clone()
} else if let ReferenceBase::Object(ref base) = self.base {
base.clone()
} else {
JsValue::Undefined
}
}
}
pub type EvalResult = Result<Completion, JErrorType>;
pub type ValueResult = Result<JsValue, JErrorType>;
pub type ReferenceResult = Result<Reference, JErrorType>;