diff --git a/src/analysis_a/dependency_res.rs b/src/analysis_a/dependency_res.rs new file mode 100644 index 0000000..aca4236 --- /dev/null +++ b/src/analysis_a/dependency_res.rs @@ -0,0 +1,206 @@ +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; + +use crate::{ + frontend::{ + ast::{DependencyPath, PathAction}, + source::SourceRef, + }, + pir::ir::{ExprRef, InsRef, KeyValueBindings, PIRIns, PIRModule, PIRModulePass}, +}; + +#[derive(Clone)] +#[allow(dead_code)] +pub struct DependencyResolvr<'a> { + module: Option<&'a PIRModule>, + file_path: String, + resolution_errors: Vec<(String, SourceRef)>, +} + +// expect to first process the module and get a Vec as the result +// we can then use these indices to get the corresponding ins from the module +// for each of these dependencies, we will: +// - process the actions until we get to a file path. The remainder of the actions will +// be the path to the dependency. +impl<'a> DependencyResolvr<'a> { + pub fn resolve(&mut self, dependencies: Vec) { + let module = self.get_module(); + let ins_pool = &module.ins_pool.pool; + + // for each dependency, we will: + // - get the Instruction (UseDependency) + // - each UseDependency has a list of DependencyPaths: + // - each of the DependencyPaths has a list of actions which will be used to get + // the path + // - we will process the actions (while updating depenedency path) until we: + // * get to a file path. Stop. + // * get to a folder. Continue. + // * path is invalid. Error. + // - once we have a valid file path, whatever is left of the actions + // will be the path to the dependency + // - cluster the dependencies by their paths and return that structure + + let mut res: HashMap> = HashMap::new(); + + for index in dependencies { + let dep = ins_pool.get(index).unwrap(); + if let PIRIns::UseDependency { paths, src: _ } = dep { + for path in paths { + let resolved_res = self.evaluate_dependency_path(path); + match resolved_res { + Ok((res_path, rem_actions)) => { + // add to res + let res_vec = res.entry(index).or_insert(Vec::new()); + res_vec.push((res_path, rem_actions)); + } + Err(msg) => { + self.resolution_errors.push((msg, path.source_ref())); + } + } + } + } + } + + // show contents of res array + for (index, m) in res { + let dep = ins_pool.get(index).unwrap(); + println!("{} resolves to the following path:", dep.as_str()); + for (path, actions) in m { + println!("\t{}: {}", path.display(), actions.as_str()); + } + } + } + + fn evaluate_dependency_path( + &mut self, + dep: &DependencyPath, + ) -> Result<(PathBuf, DependencyPath), String> { + let mut start_dir = PathBuf::from(&self.file_path.clone()); + start_dir.pop(); + let mut search_dep_path = start_dir; + let mut skip_to = 0; + + for action in &dep.actions { + match action { + PathAction::ToParentDir(_) => { + search_dep_path.pop(); + } + PathAction::ImportAll(_) => { + break; + } + PathAction::SearchFor(path_section) => { + // append path_section to search_dep_path + search_dep_path.push(path_section.as_str()); + } + PathAction::SearchCoreModulesFor(_) => todo!(), + PathAction::SearchProjectRootFor(_) => todo!(), + PathAction::SearchCurrentFileFor(_) => { + search_dep_path = PathBuf::from(&self.file_path); + search_dep_path.set_extension("pr"); + break; + } + PathAction::NameLastItemAs(_) => todo!(), + } + + // check that updated path exists + let (path_exists, is_file, is_dir) = self.path_exists(&search_dep_path); + if !path_exists { + // report error + let msg = format!("Unable to resolve dependency path: {}", dep.as_str()); + return Err(msg); + } + + // update skip_to by 1, with a max of actions.len() + skip_to += 1; + if skip_to >= dep.actions.len() { + break; + } + + if is_dir { + // continue + continue; + } + + if is_file { + // stop + break; + } else { + } + } + + // we have to verify that the path is a file + let (path_exists, is_file, _) = self.path_exists(&search_dep_path); + if !path_exists { + // report error + let msg = format!("Unable to resolve dependency path: {}", dep.as_str()); + return Err(msg); + } + + if !is_file { + // report error + let msg = format!("Dependency path must contain a file: {}", dep.as_str()); + return Err(msg); + } + + // we have a valid file path + // we need to collect the remainder of the actions into a Vector of PathActions + let mut remainder = Vec::new(); + for action in &dep.actions[skip_to..] { + remainder.push(action.clone()); + } + let remainder = DependencyPath { actions: remainder }; + Ok((search_dep_path, remainder)) + } + + // checks if path exists and also if it is a file + fn path_exists(&self, path: &PathBuf) -> (bool, bool, bool) { + let mut file_path = path.clone(); + file_path.set_extension("pr"); + let file_path = Path::new(&file_path); + let file_exists = file_path.exists(); + let dir_exists = path.exists(); + (dir_exists || file_exists, file_exists, dir_exists) + } +} + +impl<'a> PIRModulePass<'a, (), (), (), Vec, ()> for DependencyResolvr<'a> { + fn process_ins(&mut self, _: &InsRef) -> Result<(), ()> { + Ok(()) + } + + fn process_expr(&mut self, _: &ExprRef) -> Result<(), ()> { + Ok(()) + } + + fn process_pairs(&mut self, _: &KeyValueBindings) -> Result<(), ()> { + Ok(()) + } + + fn process(&mut self) -> Result, ()> { + let module = self.get_module(); + let ins_pool = &module.ins_pool.pool; + let mut dependencies = Vec::new(); + + for (index, ins) in ins_pool.iter().enumerate() { + if matches!(ins, PIRIns::UseDependency { paths: _, src: _ }) { + dependencies.push(index); + } + } + + Ok(dependencies) + } + + fn new(module: &'a PIRModule) -> Self { + Self { + module: Some(module), + file_path: module.path.clone(), + resolution_errors: Vec::new(), + } + } + + fn get_module(&mut self) -> &'a PIRModule { + self.module.unwrap() + } +} diff --git a/src/analysis_a/mod.rs b/src/analysis_a/mod.rs new file mode 100644 index 0000000..bffc631 --- /dev/null +++ b/src/analysis_a/mod.rs @@ -0,0 +1 @@ +pub mod dependency_res; diff --git a/src/frontend/ast.rs b/src/frontend/ast.rs index d16a931..79ea3f5 100644 --- a/src/frontend/ast.rs +++ b/src/frontend/ast.rs @@ -208,7 +208,6 @@ pub enum PathAction { SearchFor(Expr), SearchCoreModulesFor(Expr), SearchProjectRootFor(Expr), - SearchLastModuleFor(Expr), SearchCurrentFileFor(Expr), NameLastItemAs(Expr), } @@ -222,7 +221,6 @@ impl PathAction { PathAction::SearchFor(_) => true, PathAction::SearchCoreModulesFor(_) => true, PathAction::SearchProjectRootFor(_) => true, - PathAction::SearchLastModuleFor(_) => true, PathAction::SearchCurrentFileFor(_) => true, PathAction::ImportAll(_) => false, } @@ -235,7 +233,6 @@ impl PathAction { PathAction::NameLastItemAs(_) => true, PathAction::SearchCoreModulesFor(_) => true, PathAction::SearchProjectRootFor(_) => true, - PathAction::SearchLastModuleFor(_) => true, PathAction::SearchCurrentFileFor(_) => false, PathAction::ImportAll(_) => true, } @@ -248,7 +245,6 @@ impl PathAction { PathAction::NameLastItemAs(_) => false, PathAction::SearchCoreModulesFor(_) => true, PathAction::SearchProjectRootFor(_) => true, - PathAction::SearchLastModuleFor(_) => true, PathAction::SearchCurrentFileFor(_) => false, PathAction::ImportAll(_) => false, } @@ -261,7 +257,6 @@ impl PathAction { PathAction::NameLastItemAs(alias) => format!(" as {}", alias.as_str()), PathAction::SearchCoreModulesFor(e) => format!("@{}", e.as_str()), PathAction::SearchProjectRootFor(m) => format!("${}", m.as_str()), - PathAction::SearchLastModuleFor(n) => n.as_str(), PathAction::SearchCurrentFileFor(inner_m) => format!("!{}", inner_m.as_str()), PathAction::ImportAll(_) => "*".to_string(), } @@ -273,7 +268,6 @@ impl PathAction { PathAction::SearchFor(e) => e.source_ref(), PathAction::SearchCoreModulesFor(e) => e.source_ref(), PathAction::SearchProjectRootFor(e) => e.source_ref(), - PathAction::SearchLastModuleFor(e) => e.source_ref(), PathAction::SearchCurrentFileFor(e) => e.source_ref(), PathAction::NameLastItemAs(e) => e.source_ref(), PathAction::ImportAll(src) => src.clone(), @@ -303,6 +297,17 @@ impl DependencyPath { let last_action = self.actions.last().unwrap(); first_action.source_ref().combine(last_action.source_ref()) } + + pub fn as_str(&self) -> String { + let mut s = String::new(); + for (index, action) in self.actions.iter().enumerate() { + s.push_str(&action.as_str()); + if index < self.actions.len() - 1 { + s.push_str("::"); + } + } + s + } } #[derive(Debug, Clone)] diff --git a/src/main.rs b/src/main.rs index 8436e87..311da50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use std::{env, fs, path::PathBuf}; +use analysis_a::dependency_res::DependencyResolvr; use frontend::{ lexer::Lexer, parser::Parser, @@ -8,8 +9,9 @@ use frontend::{ }; use pir::ir::{PIRModule, PIRModulePass}; -use crate::tools::pfmt::Pfmt; +// use crate::tools::pfmt::Pfmt; +mod analysis_a; mod frontend; mod pastel; mod pir; @@ -46,6 +48,7 @@ enum Stage { Lexer, Parser, PfmtFile, + DependencyResolvr, } #[allow(dead_code)] @@ -107,6 +110,7 @@ fn create_config(args: Vec) -> ProtoConfig { "lex" => max_stage = Stage::Lexer, "parse" => max_stage = Stage::Parser, "fmt" => max_stage = Stage::PfmtFile, + "dep" => max_stage = Stage::DependencyResolvr, "dbg" => dbg_info = true, "help" => show_help = true, _ => {} @@ -207,15 +211,23 @@ fn main() { let mut ir_mod = PIRModule::new(module, path); if let Stage::PfmtFile = config.max_stage { - let mut pfmt = Pfmt::new(&mut ir_mod); - let res = pfmt.process(); + // let mut pfmt = Pfmt::new(&mut ir_mod); + // let res = pfmt.process(); + // match res { + // Ok(msg) if config.dbg_info => reporter.show_info(msg), + // Err(e) => reporter.show_error(e), + // _ => {} + // } + } + + if let Stage::DependencyResolvr = config.max_stage { + let mut dep_resolvr = DependencyResolvr::new(&mut ir_mod); + let res = dep_resolvr.process(); match res { - Ok(msg) => { - if config.dbg_info { - reporter.show_info(msg); - } + Ok(indices) => { + let _ = dep_resolvr.resolve(indices); } - Err(e) => reporter.show_error(e), + Err(_) => todo!(), } } } diff --git a/src/pir/ir.rs b/src/pir/ir.rs index 57437fb..963a3d2 100644 --- a/src/pir/ir.rs +++ b/src/pir/ir.rs @@ -147,29 +147,29 @@ impl ExprPool { } } - pub fn lowir(&mut self, expr: Expr) -> ExprRef { + pub fn to_pir(&mut self, expr: Expr) -> ExprRef { match expr { Expr::Id(id, t) => self.add(PIRExpr::Id(id, t)), Expr::Number(n, t) => self.add(PIRExpr::Number(n, t)), Expr::StringLiteral(s, t) => self.add(PIRExpr::StringLiteral(s, t)), Expr::CharacterLiteral(c, t) => self.add(PIRExpr::CharacterLiteral(c, t)), Expr::Binary(op, lhs, rhs, t) => { - let lhs = self.lowir(*lhs); - let rhs = self.lowir(*rhs); + let lhs = self.to_pir(*lhs); + let rhs = self.to_pir(*rhs); self.add(PIRExpr::Binary(op, lhs, rhs, t)) } Expr::Comparison(op, lhs, rhs, t) => { - let lhs = self.lowir(*lhs); - let rhs = self.lowir(*rhs); + let lhs = self.to_pir(*lhs); + let rhs = self.to_pir(*rhs); self.add(PIRExpr::Comparison(op, lhs, rhs, t)) } Expr::Boolean(b, t) => self.add(PIRExpr::Boolean(b, t)), Expr::Unary(op, expr, t) => { - let expr = self.lowir(*expr); + let expr = self.to_pir(*expr); self.add(PIRExpr::Unary(op, expr, t)) } Expr::Grouped(expr, t, src) => { - let expr = self.lowir(*expr); + let expr = self.to_pir(*expr); self.add(PIRExpr::Grouped(expr, t, src)) } Expr::FnCall { @@ -178,10 +178,10 @@ impl ExprPool { span, fn_type, } => { - let func = self.lowir(*func); + let func = self.to_pir(*func); let args = args .into_iter() - .map(|arg| self.lowir(arg)) + .map(|arg| self.to_pir(arg)) .collect::>(); self.add(PIRExpr::FnCall { func, @@ -196,8 +196,8 @@ impl ExprPool { src, resolved_type, } => { - let module = self.lowir(*module); - let target = self.lowir(*target); + let module = self.to_pir(*module); + let target = self.to_pir(*target); self.add(PIRExpr::ScopeInto { module, target, @@ -211,8 +211,8 @@ impl ExprPool { resolved_type, src, } => { - let directive = self.lowir(*directive); - let expr = expr.map(|expr| self.lowir(*expr)); + let directive = self.to_pir(*directive); + let expr = expr.map(|expr| self.to_pir(*expr)); self.add(PIRExpr::DirectiveExpr { directive, expr, @@ -226,7 +226,7 @@ impl ExprPool { src, resolved_type, } => { - let name = self.lowir(*name); + let name = self.to_pir(*name); let fields = self.pir_bindings(fields); self.add(PIRExpr::NamedStructInit { name, @@ -243,9 +243,9 @@ impl ExprPool { .pairs .iter() .map(|pair| { - let key = self.lowir(pair.0.clone()); + let key = self.to_pir(pair.0.clone()); if let Some(value) = pair.1.clone() { - let value = self.lowir(value); + let value = self.to_pir(value); (key, Some(value)) } else { (key, None) @@ -554,7 +554,7 @@ impl InsPool { self.add(ins) } Instruction::NamedStructDecl { name, fields, src } => { - let name_ref = epool.lowir(name); + let name_ref = epool.to_pir(name); let fields = epool.pir_bindings(fields); let ins = PIRIns::NamedStructDecl { name: name_ref, @@ -570,7 +570,7 @@ impl InsPool { src_ref, is_public, } => { - let init_expr = epool.lowir(init_expr); + let init_expr = epool.to_pir(init_expr); let ins = PIRIns::ConstantDecl { const_name, const_type, @@ -581,18 +581,18 @@ impl InsPool { self.add(ins) } Instruction::VariableDecl(name, var_type, init_expr, span) => { - let init_expr = init_expr.map(|e| epool.lowir(e)); + let init_expr = init_expr.map(|e| epool.to_pir(e)); let ins = PIRIns::VariableDecl(name, var_type, init_expr, span); self.add(ins) } Instruction::AssignmentIns(dest, target) => { - let dest = epool.lowir(dest); - let target = epool.lowir(target); + let dest = epool.to_pir(dest); + let target = epool.to_pir(target); let ins = PIRIns::AssignmentIns(dest, target); self.add(ins) } Instruction::ExpressionIns(expr, semi) => { - let expr = epool.lowir(expr); + let expr = epool.to_pir(expr); let ins = PIRIns::ExpressionIns(expr, semi); self.add(ins) } @@ -604,7 +604,7 @@ impl InsPool { is_public, src, } => { - let params = params.into_iter().map(|p| epool.lowir(p)).collect(); + let params = params.into_iter().map(|p| epool.to_pir(p)).collect(); let body = self.to_pir(epool, *body); let ins = PIRIns::FunctionDef { name, @@ -626,7 +626,7 @@ impl InsPool { condition, body, } => { - let condition = epool.lowir(condition); + let condition = epool.to_pir(condition); let body = self.to_pir(epool, *body); let ins = PIRIns::WhileLoop { src, @@ -649,7 +649,7 @@ impl InsPool { src, is_public, } => { - let name = epool.lowir(name); + let name = epool.to_pir(name); let body = self.to_pir(epool, *body); let ins = PIRIns::Module { name, @@ -660,7 +660,7 @@ impl InsPool { self.add(ins) } Instruction::Return { src, value } => { - let value = value.map(|v| epool.lowir(v)); + let value = value.map(|v| epool.to_pir(v)); let ins = PIRIns::Return { src, value }; self.add(ins) } @@ -681,7 +681,7 @@ impl InsPool { block, src, } => { - let directive = epool.lowir(directive); + let directive = epool.to_pir(directive); let block = block.map(|b| self.to_pir(epool, *b)); let ins = PIRIns::DirectiveInstruction { directive, @@ -695,7 +695,7 @@ impl InsPool { .into_iter() .map(|(cond, body)| { if let Some(cond) = cond { - let cond = epool.lowir(cond); + let cond = epool.to_pir(cond); let body = self.to_pir(epool, *body); (Some(cond), body) } else {