pax-language 0.39.1

Pax language parser
Documentation
use std::collections::HashMap;

use pax_runtime_api::{LocalProperty, PaxValue, Variable};

use super::{
    PaxAccessor, PaxExpression, PaxInfix, PaxNullCoalesce, PaxPostfix, PaxPrefix, PaxPrimary,
    PaxTernary,
};

/// Trait for resolving identifiers to values
/// This is implemented by RuntimePropertyStackFrame
pub trait IdentifierResolver {
    fn resolve(&self, name: String) -> Result<Variable, String>;
}

/// Walk an expression tree and report the symbols that should dirty-watch it.
pub trait DependencyCollector {
    fn collect_dependencies(&self) -> Vec<String>;
}

impl DependencyCollector for PaxExpression {
    fn collect_dependencies(&self) -> Vec<String> {
        match self {
            PaxExpression::Primary(p) => p.collect_dependencies(),
            PaxExpression::Prefix(p) => p.collect_dependencies(),
            PaxExpression::Infix(p) => p.collect_dependencies(),
            PaxExpression::Postfix(p) => p.collect_dependencies(),
            PaxExpression::Ternary(p) => p.collect_dependencies(),
            PaxExpression::NullCoalesce(p) => p.collect_dependencies(),
        }
    }
}

impl DependencyCollector for PaxPrimary {
    fn collect_dependencies(&self) -> Vec<String> {
        let mut ret = match self {
            PaxPrimary::Literal(_) => vec![],
            PaxPrimary::Grouped(expr, _) => expr.collect_dependencies(),
            PaxPrimary::Identifier(i, accessors) => {
                let mut deps = vec![i.name.clone()];
                for accessor in accessors {
                    if let PaxAccessor::List(index) = accessor {
                        deps.extend(index.collect_dependencies());
                    }
                }
                deps
            }
            PaxPrimary::Object(o) => o
                .iter()
                .flat_map(|(_, v)| v.collect_dependencies())
                .collect(),
            PaxPrimary::FunctionOrEnum(_, _, args) => {
                args.iter().flat_map(|a| a.collect_dependencies()).collect()
            }
            PaxPrimary::Range(start, end) => {
                let mut deps = start.collect_dependencies();
                deps.extend(end.collect_dependencies());
                deps
            }
            PaxPrimary::Tuple(t) => t.iter().flat_map(|e| e.collect_dependencies()).collect(),
            PaxPrimary::List(l) => l.iter().flat_map(|e| e.collect_dependencies()).collect(),
        };
        // Keep first occurrence order: these dependencies are serialized into
        // generated manifests and baked programs, whose identity must be stable.
        let mut seen = std::collections::HashSet::new();
        ret.retain(|dependency| seen.insert(dependency.clone()));
        ret
    }
}

impl DependencyCollector for PaxPrefix {
    fn collect_dependencies(&self) -> Vec<String> {
        self.rhs.collect_dependencies()
    }
}

impl DependencyCollector for PaxInfix {
    fn collect_dependencies(&self) -> Vec<String> {
        let mut deps = self.lhs.collect_dependencies();
        deps.extend(self.rhs.collect_dependencies());
        deps
    }
}

impl DependencyCollector for PaxPostfix {
    fn collect_dependencies(&self) -> Vec<String> {
        self.lhs.collect_dependencies()
    }
}

impl DependencyCollector for PaxTernary {
    fn collect_dependencies(&self) -> Vec<String> {
        let mut deps = self.condition.collect_dependencies();
        deps.extend(self.then_branch.collect_dependencies());
        deps.extend(self.else_branch.collect_dependencies());
        deps
    }
}

impl DependencyCollector for PaxNullCoalesce {
    fn collect_dependencies(&self) -> Vec<String> {
        let mut deps = self.lhs.collect_dependencies();
        deps.extend(self.rhs.collect_dependencies());
        deps
    }
}

impl IdentifierResolver for HashMap<String, PaxValue> {
    fn resolve(&self, name: String) -> Result<Variable, String> {
        self.get(&name)
            // A value map supplies local snapshots, not shared application state.
            // Resolving it must not require a PropertyGraph attachment.
            .map(|v| Variable::new_from_typed_property(LocalProperty::new(v.clone())))
            .ok_or(format!("Identifier not found: {}", name))
    }
}