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(¤t_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();
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())),
},
}
}
}