lox-lang 0.0.3

A Lox language runtime for Rust
Documentation
use crate::Fun;

#[derive(Clone, Copy)]
pub(super) enum FunType {
    Script,
    Function,
    Method,
    Initializer,
}

#[derive(Debug)]
pub(super) struct Local<'compile> {
    pub(super) name: &'compile str,
    pub(super) depth: usize,
    pub(super) is_defined: bool,
    pub(super) is_captured: bool,
}

#[derive(Clone, Copy, Debug)]
pub(crate) struct Upvalue {
    pub index: usize,
    pub is_local: bool,
}

pub(super) struct FunWrapper<'compile> {
    pub(super) enclosing: Option<Box<Self>>,
    pub(super) inner: Fun,
    pub(super) r#type: FunType,
    pub(super) locals: Vec<Local<'compile>>,
    pub(super) upvalues: Vec<Upvalue>,
    pub(super) scope_depth: usize,
}

impl<'compile> FunWrapper<'compile> {
    pub(super) fn new<T: ToString>(name: &T, r#type: FunType) -> Self {
        Self {
            enclosing: None,
            inner: Fun::new(name, 0),
            r#type,
            locals: vec![Local {
                name: if let FunType::Method | FunType::Initializer = r#type {
                    "this"
                } else {
                    ""
                },
                depth: 0,
                is_defined: true,
                is_captured: false,
            }],
            upvalues: Vec::new(),
            scope_depth: 0,
        }
    }

    pub(super) fn resolve_local(&self, query: &str) -> Option<(usize, bool)> {
        for (
            index,
            Local {
                name, is_defined, ..
            },
        ) in self.locals.iter().enumerate().rev()
        {
            if *name == query {
                return Some((index, *is_defined));
            }
        }

        None
    }

    pub(super) fn resolve_upvalue(&mut self, query: &str) -> Option<usize> {
        if let Some(parent) = &mut self.enclosing {
            if let Some((index, _)) = parent.resolve_local(query) {
                parent.locals[index].is_captured = true;
                return Some(self.add_upvalue(index, true));
            } else if let Some(index) = parent.resolve_upvalue(query) {
                return Some(self.add_upvalue(index, false));
            }
        }

        None
    }

    pub(super) fn add_upvalue(&mut self, local_index: usize, is_local: bool) -> usize {
        for (idx, u_val) in self.upvalues.iter().enumerate() {
            if u_val.index == local_index && u_val.is_local == is_local {
                return idx;
            }
        }

        self.upvalues.push(Upvalue {
            index: local_index,
            is_local,
        });
        self.upvalues.len() - 1
    }
}

#[derive(Debug)]
pub(super) struct ClassWrapper {
    pub(super) enclosing: Option<Box<Self>>,
    pub(super) name: Box<str>,
    pub(super) has_superclass: bool,
}