just-engine 0.1.0

A ground-up ES6 JavaScript engine with tree-walking interpreter, bytecode VMs, and Cranelift JIT compiler
Documentation
use crate::parser::ast::IdentifierData;

pub struct TriStateBool {
    flag: Option<bool>,
}
impl TriStateBool {
    pub(crate) fn new_unset() -> Self {
        TriStateBool { flag: None }
    }

    pub(crate) fn is_true(&self) -> bool {
        self.flag.is_some() && self.flag.unwrap()
    }

    pub(crate) fn is_false(&self) -> bool {
        self.flag.is_some() && !self.flag.unwrap()
    }

    pub(crate) fn make_true(&mut self) {
        self.flag = Some(true);
    }

    pub(crate) fn merge<F>(&mut self, other: TriStateBool, conflict_resolver: F)
    where
        F: Fn(bool, bool) -> bool,
    {
        self.flag = if let Some(f) = self.flag {
            if let Some(f2) = other.flag {
                if f == f2 {
                    Some(f)
                } else {
                    Some(conflict_resolver(f, f2))
                }
            } else {
                Some(false)
            }
        } else {
            other.flag
        };
    }
}
impl PartialEq for TriStateBool {
    fn eq(&self, other: &Self) -> bool {
        if let Some(f) = &self.flag {
            if let Some(f2) = &other.flag {
                *f == *f2
            } else {
                false
            }
        } else {
            if let Some(_) = &other.flag {
                false
            } else {
                true
            }
        }
    }
}

pub struct Semantics {
    pub(crate) bound_names: Vec<IdentifierData>,
    pub(crate) lexically_declared_names: Vec<IdentifierData>,
    pub(crate) var_declared_names: Vec<IdentifierData>,
    pub(crate) top_level_lexically_declared_names: Vec<IdentifierData>,
    pub(crate) top_level_var_declared_names: Vec<IdentifierData>,
    pub(crate) has_direct_super: TriStateBool,
    pub(crate) is_valid_simple_assignment_target: TriStateBool,
    pub(crate) contains_yield_expression: TriStateBool,
    pub(crate) contains_unpaired_continue: TriStateBool,
    pub(crate) contains_unpaired_break: TriStateBool,
    pub(crate) contains_super_property: TriStateBool,
    pub(crate) contains_super_call: TriStateBool,
}
impl Semantics {
    pub(crate) fn new_empty() -> Self {
        Semantics {
            bound_names: vec![],
            lexically_declared_names: vec![],
            var_declared_names: vec![],
            top_level_lexically_declared_names: vec![],
            top_level_var_declared_names: vec![],
            has_direct_super: TriStateBool::new_unset(),
            is_valid_simple_assignment_target: TriStateBool::new_unset(),
            contains_yield_expression: TriStateBool::new_unset(),
            contains_unpaired_continue: TriStateBool::new_unset(),
            contains_unpaired_break: TriStateBool::new_unset(),
            contains_super_property: TriStateBool::new_unset(),
            contains_super_call: TriStateBool::new_unset(),
        }
    }

    pub(crate) fn merge(&mut self, mut other: Self) -> &mut Self {
        let panic_on_resolve = |f, f2| {
            panic!(
                "Not sure how to resolve this conflict: (f, f2) = ({},{})",
                f, f2
            );
        };
        let true_wins = |f, f2| f || f2;

        self.bound_names.append(&mut other.bound_names);
        self.lexically_declared_names
            .append(&mut other.lexically_declared_names);
        self.has_direct_super
            .merge(other.has_direct_super, panic_on_resolve);
        self.is_valid_simple_assignment_target
            .merge(other.is_valid_simple_assignment_target, panic_on_resolve);
        self.contains_yield_expression
            .merge(other.contains_yield_expression, true_wins);
        self.contains_unpaired_continue
            .merge(other.contains_unpaired_continue, true_wins);
        self.contains_unpaired_break
            .merge(other.contains_unpaired_break, true_wins);
        self.contains_super_property
            .merge(other.contains_super_property, true_wins);
        self.contains_super_call
            .merge(other.contains_super_call, true_wins);
        self
    }
}