lox_one 0.1.0

A tree-walking interpreter for the Lox programming language.
Documentation
use std::collections::HashMap;

use crate::lox_value::LoxValue;

use super::globals::_print;

#[derive(Debug, Clone)]
pub struct Environment {
    scopes: Vec<HashMap<String, LoxValue>>,
}

impl Environment {
    pub fn new() -> Environment {
        Environment {
            scopes: vec![HashMap::new()],
        }
    }

    pub fn begin_scope(&mut self) {
        self.scopes.push(HashMap::new());
    }

    pub fn end_scope(&mut self) {
        if self.scopes.len() < 2 {
            panic!("You can't end the global scope dumbass")
        }
        self.scopes.pop();
    }

    pub fn get(&self, name: &str) -> Option<LoxValue> {
        for scope in self.scopes.iter().rev() {
            if scope.contains_key(name) {
                return scope.get(name).map(|v| v.to_owned());
            }
        }

        None
    }

    pub fn get_at(&self, name: &str, depth: usize) -> Option<LoxValue> {
        self.scopes[depth].get(name).map(|v| v.to_owned())
    }

    pub fn assign_at(&mut self, name: &str, value: LoxValue, depth: usize) -> Option<()> {
        if self.scopes[depth].contains_key(name) {
            self.scopes[depth].insert(name.to_string(), value);
            Some(())
        } else {
            None
        }
    }

    pub fn define(&mut self, name: &str, initializer: LoxValue) {
        self.scopes
            .last_mut()
            .unwrap()
            .insert(name.to_string(), initializer);
    }

    pub fn assign(&mut self, name: &str, value: LoxValue) -> Option<()> {
        for scope in self.scopes.iter_mut().rev() {
            if scope.contains_key(name) {
                scope.insert(name.to_string(), value);
                return Some(());
            }
        }

        None
    }
}