Skip to content

Commit

Permalink
Started dependency resolution pass
Browse files Browse the repository at this point in the history
  • Loading branch information
pepplejoshua committed Jul 6, 2023
1 parent 98dccba commit a1a2138
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 42 deletions.
206 changes: 206 additions & 0 deletions src/analysis_a/dependency_res.rs
Original file line number Diff line number Diff line change
@@ -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<usize> 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<usize>) {
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<usize, Vec<(PathBuf, DependencyPath)>> = 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<usize>, ()> 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<Vec<usize>, ()> {
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()
}
}
1 change: 1 addition & 0 deletions src/analysis_a/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod dependency_res;
17 changes: 11 additions & 6 deletions src/frontend/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ pub enum PathAction {
SearchFor(Expr),
SearchCoreModulesFor(Expr),
SearchProjectRootFor(Expr),
SearchLastModuleFor(Expr),
SearchCurrentFileFor(Expr),
NameLastItemAs(Expr),
}
Expand All @@ -222,7 +221,6 @@ impl PathAction {
PathAction::SearchFor(_) => true,
PathAction::SearchCoreModulesFor(_) => true,
PathAction::SearchProjectRootFor(_) => true,
PathAction::SearchLastModuleFor(_) => true,
PathAction::SearchCurrentFileFor(_) => true,
PathAction::ImportAll(_) => false,
}
Expand All @@ -235,7 +233,6 @@ impl PathAction {
PathAction::NameLastItemAs(_) => true,
PathAction::SearchCoreModulesFor(_) => true,
PathAction::SearchProjectRootFor(_) => true,
PathAction::SearchLastModuleFor(_) => true,
PathAction::SearchCurrentFileFor(_) => false,
PathAction::ImportAll(_) => true,
}
Expand All @@ -248,7 +245,6 @@ impl PathAction {
PathAction::NameLastItemAs(_) => false,
PathAction::SearchCoreModulesFor(_) => true,
PathAction::SearchProjectRootFor(_) => true,
PathAction::SearchLastModuleFor(_) => true,
PathAction::SearchCurrentFileFor(_) => false,
PathAction::ImportAll(_) => false,
}
Expand All @@ -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(),
}
Expand All @@ -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(),
Expand Down Expand Up @@ -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)]
Expand Down
28 changes: 20 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{env, fs, path::PathBuf};

use analysis_a::dependency_res::DependencyResolvr;
use frontend::{
lexer::Lexer,
parser::Parser,
Expand All @@ -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;
Expand Down Expand Up @@ -46,6 +48,7 @@ enum Stage {
Lexer,
Parser,
PfmtFile,
DependencyResolvr,
}

#[allow(dead_code)]
Expand Down Expand Up @@ -107,6 +110,7 @@ fn create_config(args: Vec<String>) -> 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,
_ => {}
Expand Down Expand Up @@ -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!(),
}
}
}
Loading

0 comments on commit a1a2138

Please sign in to comment.