celsium 0.1.7

A library for building interpreters
Documentation
use std::collections::LinkedList;
use crate::{ module::FuncArg, ObjectFieldType, Scope, BuiltinTypes };

#[derive(Debug, Clone, PartialEq)]
pub struct CompileTimeVariable {
    pub id: usize,
    pub name: String,
    pub data_type: BuiltinTypes,
    pub scope: Scope,
    pub is_exported: bool,
}

#[derive(Debug, Clone, PartialEq)]
pub struct CompileTimeImport {
    pub name: String,
    pub origin: String,
    pub imported_into: String,
}

#[derive(Clone, Debug)]
pub struct CompileTimeArray {
    pub id: usize,
    pub name: String,
    pub data_type: BuiltinTypes,
    pub length: usize,
    pub scope: Scope,
    pub is_exported: bool,
}

#[derive(Clone, Debug)]
pub struct CompileTimeFunction {
    pub id: usize,
    pub name: String,
    pub arguments: Vec<FuncArg>,
    pub scope: Scope,
    pub return_type: Option<BuiltinTypes>,
    pub is_exported: bool,
}

#[derive(Debug, Clone)]
pub struct ObjectDefinitionDefinition {
    pub module_defined_in: String,
    pub name: String,
    pub fields: Vec<ObjectFieldType>,
}

#[derive(Debug, Clone)]
pub struct CompileTimeObject {
    pub id: usize,
    pub name: String,
    pub data_type: BuiltinTypes,
    pub scope: Scope,
    pub is_exported: bool,
}

#[derive(Clone, Debug)]
pub struct CompileTimeHelper {
    pub stack: LinkedList<BuiltinTypes>,
    pub source_files: Vec<String>,
    pub source_file_paths: Vec<String>,
    pub current_file: usize,
    pub defined_functions: Vec<CompileTimeFunction>,
    pub defined_variables: Vec<CompileTimeVariable>,
    pub defined_arrays: Vec<CompileTimeArray>,
    pub defined_object_definitions: Vec<ObjectDefinitionDefinition>,
    pub defined_objects: Vec<CompileTimeObject>,
    definition_counter: usize,
    pub imports: Vec<CompileTimeImport>,
    pub compile_time_errors: Vec<CompilerError>
}

#[derive(Clone, Debug)]
pub struct CompilerError{
    pub message: String,
    pub line: Option<usize>,
    pub file: String
}

impl CompileTimeHelper {
    pub fn new(source_file: String, path: String) -> CompileTimeHelper {
        CompileTimeHelper {
            stack: LinkedList::new(),
            source_files: vec![source_file],
            source_file_paths: vec![path.clone()],
            current_file: 0,
            defined_functions: vec![],
            defined_variables: vec![],
            defined_arrays: vec![],
            definition_counter: 0,
            imports: vec![],
            defined_object_definitions: vec![],
            defined_objects: vec![],
            compile_time_errors: vec![]
        }
    }
    pub fn define_struct(&mut self, name: String, fields: Vec<ObjectFieldType>) {
        self.defined_object_definitions.push(ObjectDefinitionDefinition {
            module_defined_in: self.source_file_paths[self.current_file].clone(),
            name,
            fields,
        });
    }

    pub fn struct_exists(&mut self, name: &str) -> Option<ObjectDefinitionDefinition> {
        for object in &self.defined_object_definitions {
            if
                object.name == name &&
                object.module_defined_in == self.source_file_paths[self.current_file]
            {
                return Some(object.clone());
            }
        }
        return None;
    }

    pub fn change_module(&mut self, file_content: String, path: String) {
        self.source_files.push(file_content.clone());
        self.source_file_paths.push(path.clone());
        self.current_file += 1;
    }
    pub fn switch_to_prev_module(&mut self) {
        self.current_file -= 1;
    }
    pub fn import(&mut self, name: String, origin: String, imported_into: String) {
        self.imports.push(CompileTimeImport { name, origin, imported_into });
    }
    pub fn push(&mut self, pushable_type: BuiltinTypes) {
        self.stack.push_back(pushable_type);
    }
    pub fn pop(&mut self) -> Option<BuiltinTypes> {
        self.stack.pop_back()
    }
    pub fn def_function(
        &mut self,
        name: String,
        arguments: Vec<FuncArg>,
        scope: Scope,
        is_exported: bool,
        return_type: Option<BuiltinTypes>
    ) -> usize {
        self.defined_functions.push(CompileTimeFunction {
            id: self.definition_counter,
            name: name,
            arguments: arguments,
            scope: scope,
            return_type: return_type,
            is_exported,
        });
        self.definition_counter += 1;
        return self.definition_counter - 1;
    }
    pub fn get_func_return_type(&mut self, id: usize) -> Option<Option<BuiltinTypes>> {
        for func in self.defined_functions.clone() {
            if func.id == id {
                return Some(func.return_type);
            }
        }
        None
    }
    pub fn get_func_args(&mut self, id: usize) -> Option<Vec<FuncArg>> {
        for func in self.defined_functions.clone() {
            if func.id == id {
                return Some(func.arguments);
            }
        }
        None
    }
    pub fn def_var(
        &mut self,
        name: String,
        data_type: BuiltinTypes,
        scope: Scope,
        is_exported: bool
    ) -> Result<usize, &str> {
        let to_be_defined = CompileTimeVariable {
            name,
            data_type,
            scope: scope.clone(),
            id: self.definition_counter,
            is_exported,
        };
        for def in &self.defined_variables {
            if def.name == to_be_defined.name && def.scope == to_be_defined.scope {
                return Err("already_defined");
            }
        }
        for def in &self.defined_objects {
            if def.name == to_be_defined.name && def.scope == to_be_defined.scope {
                return Err("already_defined");
            }
        }
        for def in &self.defined_arrays {
            if def.name == to_be_defined.name && def.scope == to_be_defined.scope {
                return Err("already_defined");
            }
        }
        for import in &self.imports {
            if import.name == to_be_defined.name && import.imported_into == scope.module_path {
                return Err("already_imported");
            }
        }
        self.defined_variables.push(to_be_defined);
        self.definition_counter += 1;
        return Ok(self.definition_counter - 1);
    }
    pub fn def_object(
        &mut self,
        name: String,
        scope: Scope,
        is_exported: bool,
        fields: Vec<ObjectFieldType>
    ) -> Result<usize, &str> {
        let object: CompileTimeObject = CompileTimeObject {
            data_type: BuiltinTypes::Object { fields: fields },
            name,
            id: self.definition_counter,
            scope: scope.clone(),
            is_exported,
        };
        for def in &self.defined_variables {
            if def.name == object.name && def.scope == object.scope {
                return Err("already_defined");
            }
        }
        for def in &self.defined_objects {
            if def.name == object.name && def.scope == object.scope {
                return Err("already_defined");
            }
        }
        for def in &self.defined_arrays {
            if def.name == object.name && def.scope == object.scope {
                return Err("already_defined");
            }
        }
        for import in &self.imports {
            if import.name == object.name && import.imported_into == scope.module_path {
                return Err("already_imported");
            }
        }
        self.defined_objects.push(object);
        self.definition_counter += 1;
        return Ok(self.definition_counter - 1);
    }
    pub fn get_object_if_exists(&mut self, name: &str) -> Option<CompileTimeObject> {
        for object in &self.defined_objects {
            if object.name == name {
                return Some(object.clone());
            }
        }
        None
    }
    pub fn get_var_type(&mut self, var_id: usize) -> Option<BuiltinTypes> {
        for var in self.defined_variables.clone() {
            if var.id == var_id {
                return Some(var.data_type);
            }
        }
        for var in self.defined_objects.clone() {
            if var.id == var_id {
                return Some(var.data_type);
            }
        }
        for var in self.defined_arrays.clone() {
            if var.id == var_id {
                return Some(BuiltinTypes::Array { element_type: Box::new(var.data_type), length: Some(var.length) });
            }
        }
        None
    }
    pub fn def_array(
        &mut self,
        name: &str,
        data_type: BuiltinTypes,
        initial_length: usize,
        scope: Scope,
        is_exported: bool
    ) -> usize {
        self.defined_arrays.push(CompileTimeArray {
            name: name.to_string(),
            data_type,
            length: initial_length,
            scope,
            id: self.definition_counter,
            is_exported,
        });

        self.definition_counter += 1;

        return self.definition_counter - 1;
    }

    pub fn get_array_type_and_length(&mut self, id: usize) -> Option<(BuiltinTypes, usize)> {
        for array in &self.defined_arrays {
            if array.id == id {
                return Some((array.data_type.clone(), array.length));
            }
        }
        None
    }
    
}