glowdust 0.0.1

A DBMS with a data model based on functions and pattern matching
Documentation
use crate::compiler::parser::ast::{FunctionDefinition, Stmt, TypeDefinition};
use crate::compiler::parser::CompileError;
use crate::compiler::value::parameters::Variable;
use crate::compiler::value::values::Value;
use std::collections::HashMap;
use tracing::trace;

#[derive(Default, Debug)]
pub struct Symbols {
    pub constants: Vec<Value>,
    pub variables: Vec<Variable>,
}

#[derive(Default, Debug)]
pub struct FunctionContext {
    pub name: String,
    pub symbols: Symbols,
}

impl FunctionContext {
    fn new(name: String) -> Self {
        FunctionContext {
            name,
            symbols: Symbols::default(),
        }
    }
}

#[derive(Default, Debug)]
pub struct ParseState {
    current_function: Option<FunctionContext>,
    current_query_block: Option<Symbols>,

    pub(crate) function_definitions: HashMap<String, Vec<(FunctionDefinition, FunctionContext)>>,
    pub(crate) type_definitions: Vec<TypeDefinition>,

    pub script_symbols: Symbols,
    pub(crate) statements: Vec<Stmt>,

    pub errors: Box<Vec<CompileError>>,
}

impl ParseState {
    pub(crate) fn declare_variable(&mut self, var_name: String) -> u8 {
        let variables;
        if let Some(current_function) = self.current_function.as_mut() {
            variables = &mut current_function.symbols.variables
        } else if let Some(symbols) = self.current_query_block.as_mut() {
            variables = &mut symbols.variables
        } else {
            variables = &mut self.script_symbols.variables;
        }
        let var_index = variables.len();
        variables.push(Variable {
            index: var_index,
            name: var_name,
            initialized: false,
        });
        var_index as u8
    }

    pub fn reset(&mut self) {
        self.current_function = None;
        self.current_query_block = None;
        self.function_definitions.clear();
        self.script_symbols.constants.clear();
        self.script_symbols.variables.clear();
        self.statements.clear();
        self.errors.clear();
        self.type_definitions.clear();
    }

    fn find_variable<'a>(variable_list: &'a [Variable], name: &str) -> Option<&'a Variable> {
        variable_list.iter().find(|var| &var.name == name)
    }

    pub(crate) fn get_variable(&self, key: &str) -> Option<&Variable> {
        if let Some(current_function) = self.current_function.as_ref() {
            return Self::find_variable(&current_function.symbols.variables, key);
        }
        if let Some(symbols) = self.current_query_block.as_ref() {
            Self::find_variable(&symbols.variables, key)
        } else {
            Self::find_variable(&self.script_symbols.variables, key)
        }
    }

    pub(crate) fn add_value_constant(&mut self, value: Value) -> u8 {
        let new_index;
        if let Some(current_function) = self.current_function.as_mut() {
            new_index = current_function.symbols.constants.len();
            // trace!(
            //     "Added constant {:?} to function, index is {}",
            //     &value,
            //     new_index,
            // );
            current_function.symbols.constants.push(value);
        } else {
            for (index, var) in self.script_symbols.constants.iter().enumerate() {
                if value.eq(var) {
                    return index as u8;
                }
            }
            new_index = self.script_symbols.constants.len();
            self.script_symbols.constants.push(value);
        }
        new_index as u8
    }

    pub(crate) fn start_query_block(&mut self) {
        if self.current_query_block.is_some() {
            panic!("Cannot handle nested query blocks");
        }
        self.current_query_block = Some(Symbols::default());
    }

    pub(crate) fn end_query_block(&mut self) {
        match &self.current_query_block {
            None => {
                panic!("Cannot end query block when one hasn't been opened yet.");
            }
            Some(_) => {
                self.current_query_block.take();
            }
        }
    }

    pub(crate) fn start_function_definition(&mut self, name: String) {
        if self.current_function.is_some() {
            panic!("Cannot handle nested function definitions");
        }
        self.current_function = Some(FunctionContext::new(name));
    }

    pub(crate) fn end_function_definition(&mut self, function: FunctionDefinition) {
        match &self.current_function {
            None => {
                panic!("Cannot end function definition when there isn't one open.");
            }
            Some(def) => match self.function_definitions.get_mut(&def.name) {
                None => {
                    self.function_definitions.insert(
                        def.name.clone(),
                        vec![(function, self.current_function.take().unwrap())],
                    );
                }
                Some(existing) => existing.push((function, self.current_function.take().unwrap())),
            },
        }
    }
}