From a9c2741527ee66e3f483e9e1dc5b30337aefb27e Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Mon, 19 Feb 2024 17:46:49 -0700 Subject: [PATCH 1/7] library2 --- Cargo.lock | 44 ++++- crates/common2/src/input.rs | 2 +- crates/driver2/Cargo.toml | 6 + crates/driver2/src/check.rs | 145 ++++++++++++++++ crates/driver2/src/lib.rs | 24 ++- crates/driver2/src/main.rs | 134 ++++++++++++--- crates/hir/src/analysis_pass.rs | 18 +- library/core/fe.toml | 3 + library/core/src/cmp.fe | 0 library/core/src/cmp/cmp.fe | 30 ++++ library/core/src/ctrl.fe | 0 library/core/src/ctrl/applicative.fe | 5 + library/core/src/ctrl/applicative/option.fe | 8 + library/core/src/ctrl/function.fe | 5 + library/core/src/ctrl/functor.fe | 9 + library/core/src/ctrl/functor/option.fe | 13 ++ library/core/src/ctrl/monad copy.fe | 173 ++++++++++++++++++++ library/core/src/ctrl/monad.fe | 121 ++++++++++++++ library/core/src/ctrl/monad/option.fe | 13 ++ library/core/src/data.fe | 0 library/core/src/data/list.fe | 4 + library/core/src/data/map.fe | 4 + library/core/src/data/option.fe | 4 + library/core/src/data/result.fe | 4 + library/core/src/data/set.fe | 3 + library/core/src/data/string.fe | 0 library/core/src/data/tuple.fe | 1 + library/core/src/io.fe | 15 ++ library/core/src/lib.fe | 0 library/core/src/num.fe | 25 +++ library/core/src/num/arith.fe | 78 +++++++++ library/core/src/num/nat.fe | 15 ++ library/eth/fe.toml | 3 + library/eth/src/abi.fe | 0 library/eth/src/contract.fe | 18 ++ library/eth/src/lib.fe | 0 library/std/fe.toml | 3 + library/std/src/data/list.fe | 1 + library/std/src/lib.fe | 0 library/std/src/target/evm.fe | 10 ++ 40 files changed, 914 insertions(+), 27 deletions(-) create mode 100644 crates/driver2/src/check.rs create mode 100644 library/core/fe.toml create mode 100644 library/core/src/cmp.fe create mode 100644 library/core/src/cmp/cmp.fe create mode 100644 library/core/src/ctrl.fe create mode 100644 library/core/src/ctrl/applicative.fe create mode 100644 library/core/src/ctrl/applicative/option.fe create mode 100644 library/core/src/ctrl/function.fe create mode 100644 library/core/src/ctrl/functor.fe create mode 100644 library/core/src/ctrl/functor/option.fe create mode 100644 library/core/src/ctrl/monad copy.fe create mode 100644 library/core/src/ctrl/monad.fe create mode 100644 library/core/src/ctrl/monad/option.fe create mode 100644 library/core/src/data.fe create mode 100644 library/core/src/data/list.fe create mode 100644 library/core/src/data/map.fe create mode 100644 library/core/src/data/option.fe create mode 100644 library/core/src/data/result.fe create mode 100644 library/core/src/data/set.fe create mode 100644 library/core/src/data/string.fe create mode 100644 library/core/src/data/tuple.fe create mode 100644 library/core/src/io.fe create mode 100644 library/core/src/lib.fe create mode 100644 library/core/src/num.fe create mode 100644 library/core/src/num/arith.fe create mode 100644 library/core/src/num/nat.fe create mode 100644 library/eth/fe.toml create mode 100644 library/eth/src/abi.fe create mode 100644 library/eth/src/contract.fe create mode 100644 library/eth/src/lib.fe create mode 100644 library/std/fe.toml create mode 100644 library/std/src/data/list.fe create mode 100644 library/std/src/lib.fe create mode 100644 library/std/src/target/evm.fe diff --git a/Cargo.lock b/Cargo.lock index 68ed66bba8..f8d27d68d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1181,10 +1181,16 @@ dependencies = [ "camino", "clap 4.5.7", "codespan-reporting", + "dirs", "fe-common2", "fe-hir", "fe-hir-analysis", + "include_dir", "salsa 0.18.0", + "semver 1.0.23", + "serde", + "toml 0.8.14", + "walkdir", ] [[package]] @@ -3463,6 +3469,18 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.14", +] + [[package]] name = "toml_datetime" version = "0.6.6" @@ -3482,7 +3500,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -3493,7 +3511,20 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap 2.2.6", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.9", ] [[package]] @@ -3964,6 +3995,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/crates/common2/src/input.rs b/crates/common2/src/input.rs index 8da11ca76d..5bdd8dc8e3 100644 --- a/crates/common2/src/input.rs +++ b/crates/common2/src/input.rs @@ -8,7 +8,7 @@ use crate::{indexmap::IndexSet, InputDb}; #[salsa::input(constructor = __new_impl)] pub struct InputIngot { /// An absolute path to the ingot root directory. - /// The all files in the ingot should be located under this directory. + /// All files in the ingot should be located under this directory. #[return_ref] pub path: Utf8PathBuf, diff --git a/crates/driver2/Cargo.toml b/crates/driver2/Cargo.toml index 0af1b159ff..f60fbeb22d 100644 --- a/crates/driver2/Cargo.toml +++ b/crates/driver2/Cargo.toml @@ -18,3 +18,9 @@ common = { path = "../common2", package = "fe-common2" } hir-analysis = { path = "../hir-analysis", package = "fe-hir-analysis" } camino = "1.1.4" clap = { version = "4.3", features = ["derive"] } +toml = "0.8.13" +serde = { version = "1", features = ["derive"] } +semver = "1.0.23" +walkdir = "2" +include_dir = "0.7" +dirs = "5.0.1" \ No newline at end of file diff --git a/crates/driver2/src/check.rs b/crates/driver2/src/check.rs new file mode 100644 index 0000000000..eaaff90638 --- /dev/null +++ b/crates/driver2/src/check.rs @@ -0,0 +1,145 @@ +use crate::{load_ingot, CheckArgs}; +use common::indexmap::IndexSet; +use common::input::IngotDependency; +use common::{input::IngotKind, InputIngot}; +use fe_driver2::DriverDataBase; +use include_dir::{include_dir, Dir}; +use semver::Version; +use std::fs; +use std::path::PathBuf; +use std::{collections::BTreeSet, path::Path}; + +const STD_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../library/std"); + +fn write_std_files(std_path: &Path) { + write_files_recursive(&STD_DIR, std_path); +} + +fn write_files_recursive(dir: &Dir<'_>, base_path: &Path) { + for file in dir.files() { + let file_path = base_path.join(file.path()); + if let Some(parent_dir) = file_path.parent() { + std::fs::create_dir_all(parent_dir).unwrap(); + } + std::fs::write(file_path, file.contents()).unwrap(); + } + + for subdir in dir.dirs() { + let subdir_path = base_path.join(subdir.path()); + std::fs::create_dir_all(&subdir_path).unwrap(); + write_files_recursive(subdir, &base_path); + } +} + +pub fn run_check(args: &CheckArgs) { + let std_path = match &args.std_path { + Some(path) => PathBuf::from(path.to_owned()), + None => { + let home_dir = dirs::home_dir().expect("Failed to get user home directory"); + home_dir.join(".fe/std") + } + }; + if !std_path.exists() { + println!("The standard library is not installed. Do you want to perform the write? (y/n)"); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let input = input.trim().to_lowercase(); + if input == "y" || input == "yes" { + write_std_files(&std_path); + } else { + eprintln!( + "Cannot perform the write without the standard library being installed on disk" + ); + std::process::exit(2); + } + } + + let path = Path::new(&args.path); + if !path.exists() { + eprintln!("Path '{}' does not exist", path.display()); + std::process::exit(2); + } + + let mut db = DriverDataBase::default(); + + let std_ingot = load_ingot(&std_path, &mut db, IngotKind::Std, &mut IndexSet::default()); + + if path.is_file() { + let source = fs::read_to_string(path).unwrap(); + check_single_file(path, source, std_ingot, &mut db, args.dump_scope_graph); + } else if path.is_dir() { + check_ingot(path, std_ingot, &mut db, args.dump_scope_graph); + } else { + eprintln!( + "Path '{}' is neither a file nor a directory", + path.display() + ); + std::process::exit(2); + } +} + +pub fn check_single_file( + path: &Path, + source: String, + std_ingot: InputIngot, + db: &mut DriverDataBase, + dump_scope_graph: bool, +) { + let mut dependencies = IndexSet::default(); + dependencies.insert(IngotDependency::new("std", std_ingot)); + let ingot = InputIngot::new( + db, + path.parent().unwrap().to_str().unwrap(), + IngotKind::StandAlone, + Version::new(0, 1, 0), + dependencies.clone(), + ); + + // let input_file = InputFile::new( + // db, + // ingot.clone(), + // path.file_name().unwrap().to_str().unwrap().into(), + // source, + // ); + // ingot.set_files(db, BTreeSet::from([input_file.clone()])); + // ingot.set_root_file(db, input_file); + + let top_mod = db.standalone(path, &source); + // db.run_on_top_mod(top_mod); + // db.emit_diags(); + + // if dump_scope_graph { + // println!("{}", dump_scope_graph(db, top_mod)); + // } +} + +pub fn check_ingot( + path: &Path, + std_ingot: InputIngot, + db: &mut DriverDataBase, + dump_scope_graph: bool, +) { + // let mut dependencies = BTreeSet::from([IngotDependency::new("std", std_ingot)]); + let mut dependencies = IndexSet::default(); + let mut main_ingot = load_ingot(path, db, IngotKind::Local, &mut dependencies); + + // main_ingot.set_external_ingots(db, dependencies); + + let diags = db.run_on_ingot(std_ingot); + + // let diags = db.format_diags(); + // if !diags.is_empty() { + // panic!("{diags}") + // } + + // db.run_on_ingot(main_ingot); + + // let diags = db.format_diags(); + // if !diags.is_empty() { + // panic!("{:?}", diags) + // } + + // if dump_scope_graph { + // println!("{}", dump_scope_graph(db, top_mod)); + // } +} diff --git a/crates/driver2/src/lib.rs b/crates/driver2/src/lib.rs index e008526388..c8824937f8 100644 --- a/crates/driver2/src/lib.rs +++ b/crates/driver2/src/lib.rs @@ -13,8 +13,11 @@ use common::{ InputDb, InputFile, InputIngot, }; use hir::{ - analysis_pass::AnalysisPassManager, diagnostics::DiagnosticVoucher, hir_def::TopLevelMod, - lower::map_file_to_mod, HirDb, LowerHirDb, ParsingPass, SpannedHirDb, + analysis_pass::AnalysisPassManager, + diagnostics::DiagnosticVoucher, + hir_def::TopLevelMod, + lower::{map_file_to_mod, module_tree}, + HirDb, LowerHirDb, ParsingPass, SpannedHirDb, }; use hir_analysis::{ name_resolution::{DefConflictAnalysisPass, ImportAnalysisPass, PathAnalysisPass}, @@ -71,6 +74,23 @@ impl DriverDataBase { DiagnosticsCollection(pass_manager.run_on_module(top_mod)) } + pub fn run_on_ingot<'db>(&'db mut self, ingot: InputIngot) -> DiagnosticsCollection<'db> { + self.run_on_ingot_with_pass_manager(ingot, initialize_analysis_pass) + } + + pub fn run_on_ingot_with_pass_manager<'db, F>( + &'db mut self, + ingot: InputIngot, + pm_builder: F, + ) -> DiagnosticsCollection<'db> + where + F: FnOnce(&'db DriverDataBase) -> AnalysisPassManager<'db>, + { + let tree = module_tree(self, ingot); + let mut pass_manager = pm_builder(self); + DiagnosticsCollection(pass_manager.run_on_module_tree(tree)) + } + pub fn standalone(&mut self, file_path: &path::Path, source: &str) -> InputFile { let kind = IngotKind::StandAlone; diff --git a/crates/driver2/src/main.rs b/crates/driver2/src/main.rs index 1ccababa43..113ca9972d 100644 --- a/crates/driver2/src/main.rs +++ b/crates/driver2/src/main.rs @@ -1,41 +1,133 @@ -use clap::Parser; +use clap::{Args, Parser, Subcommand}; +use common::input::{IngotDependency, InputFile}; +use common::{input::IngotKind, InputDb, InputIngot}; use fe_driver2::DriverDataBase; use hir::hir_def::TopLevelMod; +use semver::Version; +use serde::Deserialize; +use std::{collections::BTreeSet, path::Path}; +use walkdir::WalkDir; +mod check; +use common::indexmap::IndexSet; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] -struct Args { - /// The file to compile. +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +enum Commands { + Check(CheckArgs), +} + +#[derive(Args, Debug)] +struct CheckArgs { + /// The path to check, either a single file or a directory. #[arg()] - file_path: String, + path: String, + + /// The std lib path. + #[arg(short, long)] + std_path: Option, /// Dump a graphviz dot file of the scope graph for the given file. #[arg(long = "dump-scope-graph", default_value_t = false)] dump_scope_graph: bool, } +#[derive(Deserialize, Debug)] +struct Manifest { + package: Package, + dependencies: Option>, +} + +#[derive(Deserialize, Debug)] +struct Package { + name: String, + version: String, +} + pub fn main() { - let args = Args::parse(); - let path = std::path::Path::new(&args.file_path); - if !path.exists() { - eprintln!("file '{}' does not exist", args.file_path); - std::process::exit(2); + let cli = Cli::parse(); + + // let mut db = DriverDataBase::default(); + // let input_file = db.standalone(path, &source); + // let top_mod = db.top_mod(input_file); + // let diags = db.run_on_top_mod(top_mod); + // diags.emit(&db); + + // if args.dump_scope_graph { + // println!("{}", dump_scope_graph(&db, top_mod)); + match &cli.command { + Commands::Check(args) => check::run_check(args), } - let source = std::fs::read_to_string(&args.file_path).unwrap(); +} + +// fn dump_scope_graph(db: &DriverDataBase, top_mod: TopLevelMod) -> String { +// let mut s = vec![]; +// top_mod.scope_graph(db).write_as_dot(db, &mut s).unwrap(); +// String::from_utf8(s).unwrap() +// } + +fn load_ingot( + path: &Path, + db: &mut dyn InputDb, + ingot_kind: IngotKind, + dependencies: &mut IndexSet, +) -> InputIngot { + let manifest_path = path.join("fe.toml"); + let manifest_content = + std::fs::read_to_string(&manifest_path).expect("Unable to read manifest file"); + let manifest: Manifest = toml::from_str(&manifest_content).expect("Invalid TOML format"); + + let project_name = &manifest.package.name; + let project_version = &manifest.package.version; - let mut db = DriverDataBase::default(); - let input_file = db.standalone(path, &source); - let top_mod = db.top_mod(input_file); - let diags = db.run_on_top_mod(top_mod); - diags.emit(&db); + let version = Version::parse(project_version).expect("Invalid version format"); - if args.dump_scope_graph { - println!("{}", dump_scope_graph(&db, top_mod)); + let ingot = InputIngot::new( + db, + path.to_str().unwrap(), + ingot_kind, + version, + IndexSet::default(), + ); + + if let Some(deps) = &manifest.dependencies { + for dep in deps { + let dep_path = path.join(dep); + let dep_ingot = load_ingot(&dep_path, db, IngotKind::External, dependencies); + dependencies.insert(IngotDependency::new(dep, dep_ingot)); + } } + + let src_path = path.join("src"); + set_src_files(&src_path, db, ingot); + + ingot } -fn dump_scope_graph(db: &DriverDataBase, top_mod: TopLevelMod) -> String { - let mut s = vec![]; - top_mod.scope_graph(db).write_as_dot(db, &mut s).unwrap(); - String::from_utf8(s).unwrap() +fn set_src_files(path: &Path, db: &mut dyn InputDb, ingot: InputIngot) { + let input_files: IndexSet<_> = WalkDir::new(path) + .into_iter() + // .expect("read_dir call failed") + .filter_map(|entry| entry.ok()) + .filter(|entry| entry.path().is_file()) + .map(|entry| { + let file_path = entry.path().to_str().unwrap().to_owned(); + let content = std::fs::read_to_string(&file_path).unwrap(); + InputFile::new(db, ingot, file_path.into(), content) + }) + .collect(); + + let root_file = input_files + .iter() + .find(|file| file.path(db).ends_with("lib.fe")) + .expect("Root file 'lib.fe' not found") + .clone(); + + ingot.set_root_file(db, root_file); + ingot.set_files(db, input_files); } diff --git a/crates/hir/src/analysis_pass.rs b/crates/hir/src/analysis_pass.rs index f162bf3c71..c37625aa8e 100644 --- a/crates/hir/src/analysis_pass.rs +++ b/crates/hir/src/analysis_pass.rs @@ -1,4 +1,7 @@ -use crate::{diagnostics::DiagnosticVoucher, hir_def::TopLevelMod}; +use crate::{ + diagnostics::DiagnosticVoucher, + hir_def::{ModuleTree, TopLevelMod}, +}; /// All analysis passes that run analysis on the HIR top level module /// granularity should implement this trait. @@ -33,4 +36,17 @@ impl<'db> AnalysisPassManager<'db> { } diags } + + pub fn run_on_module_tree( + &mut self, + tree: &'db ModuleTree<'db>, + ) -> Vec + 'db>> { + let mut diags = vec![]; + for module in tree.all_modules() { + for pass in self.module_passes.iter_mut() { + diags.extend(pass.run_on_module(module)); + } + } + diags + } } diff --git a/library/core/fe.toml b/library/core/fe.toml new file mode 100644 index 0000000000..71b5b7657e --- /dev/null +++ b/library/core/fe.toml @@ -0,0 +1,3 @@ +[package] +name = "core" +version = "1.0.0" \ No newline at end of file diff --git a/library/core/src/cmp.fe b/library/core/src/cmp.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/core/src/cmp/cmp.fe b/library/core/src/cmp/cmp.fe new file mode 100644 index 0000000000..57bf955f43 --- /dev/null +++ b/library/core/src/cmp/cmp.fe @@ -0,0 +1,30 @@ +// /// Equal (e.g. `x == y`) +// pub trait Eq { +// fn eq(self, rhs: Rhs) -> Out +// } + +// /// Not equal (e.g. `x != y`) +// pub trait NotEq { +// fn not_eq(self, rhs: Rhs) -> Out +// } + +// /// Less than (e.g. `x < y`) +// pub trait Lt { +// fn lt(self, rhs: Rhs) -> Out +// } + +// /// Less than or equal (e.g. `x <= y`) +// pub trait LtEq { +// fn lt_eq(self, rhs: Rhs) -> Out +// } + +// /// Greater than (e.g. `x > y`) +// pub trait Gt { +// fn gt(self, rhs: Rhs) -> Out +// } + +// /// Greater than or equal (e.g. `x >= y`) +// pub trait GtEq { +// fn gt_eq(self, rhs: Rhs) -> Out +// } + diff --git a/library/core/src/ctrl.fe b/library/core/src/ctrl.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/core/src/ctrl/applicative.fe b/library/core/src/ctrl/applicative.fe new file mode 100644 index 0000000000..dd828284cc --- /dev/null +++ b/library/core/src/ctrl/applicative.fe @@ -0,0 +1,5 @@ +pub trait Applicative +where Self: * -> * +{ + fn pure(value: Value) -> Self +} \ No newline at end of file diff --git a/library/core/src/ctrl/applicative/option.fe b/library/core/src/ctrl/applicative/option.fe new file mode 100644 index 0000000000..002d31de15 --- /dev/null +++ b/library/core/src/ctrl/applicative/option.fe @@ -0,0 +1,8 @@ +use ingot::data::{option::Option} +use ingot::ctrl::{applicative::Applicative, function::Fn} + +impl Applicative for Option { + fn pure(value: Value) -> Self { + Self::Some(value) + } +} diff --git a/library/core/src/ctrl/function.fe b/library/core/src/ctrl/function.fe new file mode 100644 index 0000000000..42346e4c42 --- /dev/null +++ b/library/core/src/ctrl/function.fe @@ -0,0 +1,5 @@ +use ingot::data::tuple::Tuple + +pub trait Fn where Args: Tuple { + fn exec(self, args: Args) -> Ret +} diff --git a/library/core/src/ctrl/functor.fe b/library/core/src/ctrl/functor.fe new file mode 100644 index 0000000000..ded9eb27f1 --- /dev/null +++ b/library/core/src/ctrl/functor.fe @@ -0,0 +1,9 @@ +use ingot::ctrl::{applicative::Applicative, function::Fn} +use ingot::data::tuple::Tuple + +pub trait Functor: Applicative +where Self: * -> * +{ + fn fmap(self: Self, morph: Morph) -> Self + where Morph: Fn<1, (Source), Target>, (Source): Tuple<1> +} diff --git a/library/core/src/ctrl/functor/option.fe b/library/core/src/ctrl/functor/option.fe new file mode 100644 index 0000000000..bd65b693ee --- /dev/null +++ b/library/core/src/ctrl/functor/option.fe @@ -0,0 +1,13 @@ +use ingot::ctrl::{functor::Functor, function::Fn} +use ingot::data::{option::Option, tuple::Tuple} + +impl Functor for Option { + fn fmap(self: Self, morph: Morph) -> Self + where Morph: Fn<1, (Source), Target>, (Source): Tuple<1> + { + match self { + Self::Some(self) => Self::pure(value: morph.exec(args: (self, ))) + Self::None => Self::None + } + } +} diff --git a/library/core/src/ctrl/monad copy.fe b/library/core/src/ctrl/monad copy.fe new file mode 100644 index 0000000000..4f5e1e8e47 --- /dev/null +++ b/library/core/src/ctrl/monad copy.fe @@ -0,0 +1,173 @@ +// use self::option::Option + +// trait Applicative +// where Self: * -> * +// { +// fn pure(t: T) -> Self +// } + +// impl Applicative for Option { +// fn pure(t: T) -> Self { +// Option::Some(t) +// } +// } + +// trait Monad: Applicative +// where Self: * -> * +// { +// fn bind(self: Self) -> Self where F: Fn> +// } + +// impl Monad for Option { +// fn bind(self: Self) -> Self where F: Fn> { +// match self { +// Self::Some(self) => F::exec(t: self) +// Self::None => Self::None +// } +// } +// } + +// fn foo(f: F) +// where F: Fn(u8, u8, u8) -> u8 { +// where F: Fn<{u8, u8, u8}, u8> + +// } + +// fn f(u8, u8, u8) -> u8 {} // (u8, u8, u8) -> u8 +// fn g((u8, u8, u8)) -> u8 {} //((u8,u8,u8)) -> u8 + +// fn main() { +// f(1, 2, 3) // f.exec((1, 2, 3)) + +// let x = (1, 2, 3) +// f(x) +// g(x) + +// let args = {1, 2, 3} +// args.push(1) + +// let args = (1, 2, 3) +// f (1, 2, 3) +// f args + +// let x = ((u8, u8, u8)) +// let x = ((u8, u8, u8),) + +// f(args..) // f(x, y) f ( +// } +// (u8, u8, u8) -> u8 +// u8 -> u8 -> u8 -> u8 + + + +// impl Fn<((u8, u8, u8)), u8> for G + +// impl Fn<(u8, u8, u8), u8> for Foo { + +// } + +// trait Fn where T: FnArgs { +// fn exect(&self, t: T) -> U +// } + +// trait Fn +// where Arg: Tuple +// { +// fn call(self, arg : Arg) -> Ret +// } + +// trait FnMut where T: FnArgs { +// fn exect(&mut self, t: T) -> U +// } + +// trait Tuple; + +// fn map(t: T, f: F) -> U +// where F: Fn(T) -> U {...} + +// type MyFn = () + +// impl Fn for Foo { +// fn exec(&self, t: T) -> U { +// t.element(0) +// t.len() +// } +// } + +// impl Fn<(u8, u8>, Option> for MyFn { +// fn exec(t: (bool, bool)) -> Option { +// let (a, b) = t +// f(a, b) +// } +// } + +// #test +// fn my_test() { +// let f: MyFn = () +// let a = Option::Some(true).bind<_, _, _>(f) +// let a: Option = Option::Some(true).bind(f) +// } + + +// sub x y = x - y +// f = sub 1 // f 2 == 1 - 2 +// g = `sub` 1 // g 2 == 2 - 1 + + +// enum Result { +// Ok(T) +// Err(E) +// } +// impl Functor for Result<*, E> { // or Result<_, E> maybe? +// fn map>(self: Self, _ f: F) -> Self { +// match self { +// Result::Ok(a) => { +// return Result::Ok(f(a)) +// } +// Result::Err(e) => { +// return Result::Err(e) +// } +// } +// } +// } + + +// enum Res { // Result +// Err(E) +// Ok(T) +// } +// impl Functor for Res { +// fn map>(self: Self, _ f: F) -> Self { +// match self { +// Result::Ok(a) => { +// return Result::Ok(f(a)) +// } +// Result::Err(e) => { +// return Result::Err(e) +// } +// } +// } +// } + + + +// fn main() { +// let r = foo() +// r.map(|t| ...) +// } + + +// enum Result1 + +// Result<_, E> + +// Flip (Result) + + + +// ((+) `foldl` 0) [1..5] +// ((`foldl` 0) [1..5]) (+) + +// flip :: (a -> b -> c) -> b -> a -> c +// f :: a -> b -> c -> d -> e +// flip f :: b -> a -> c -> d -> e diff --git a/library/core/src/ctrl/monad.fe b/library/core/src/ctrl/monad.fe new file mode 100644 index 0000000000..1c5a188449 --- /dev/null +++ b/library/core/src/ctrl/monad.fe @@ -0,0 +1,121 @@ +use ingot::num::arith::HAdd +use ingot::ctrl::{functor::Functor, function::Fn} +use ingot::data::tuple::Tuple + +pub trait Monad: Functor +where Self: * -> * +{ + fn bind(self: Self, _ morph: Morph) -> Self + where Morph: Fn<1, (Source), Self>, (Source): Tuple<1> +} + + +// impl HAdd> for Option { +// fn add(self, rhs: u8) -> Option { +// self.bind>(morph: BindAdd { n: rhs }) +// } +// } + +// fn test_monadd() { +// let a: Option = Option::Some(42) +// let b = 26 +// let c = a.add(rhs: b) +// } + +// type MyFn = () + +// impl Fn<1, (bool), Option> for MyFn { +// fn exec(self, args: (bool)) -> Option { +// Option::Some(0) +// } +// } + +// impl Tuple<1> for (bool) { } + +// #test +// fn my_test() { +// let f: MyFn = () +// let a = Option::Some(true).bind(f) +// } + +// fn map(t: T, f: F) -> U +// where F: Fn(T) -> U {...} + +// type MyFn = () + +// impl Fn for Foo { +// fn exec(&self, t: T) -> U { +// t.element(0) +// t.len() +// } +// } + +// impl Fn<(u8, u8>, Option> for MyFn { +// fn exec(t: (bool, bool)) -> Option { +// let (a, b) = t +// f(a, b) +// } +// } + +// sub x y = x - y +// f = sub 1 // f 2 == 1 - 2 +// g = `sub` 1 // g 2 == 2 - 1 + + +// enum Result { +// Ok(T) +// Err(E) +// } +// impl Functor for Result<*, E> { // or Result<_, E> maybe? +// fn map>(self: Self, _ f: F) -> Self { +// match self { +// Result::Ok(a) => { +// return Result::Ok(f(a)) +// } +// Result::Err(e) => { +// return Result::Err(e) +// } +// } +// } +// } + + +// enum Res { // Result +// Err(E) +// Ok(T) +// } +// impl Functor for Res { +// fn map>(self: Self, _ f: F) -> Self { +// match self { +// Result::Ok(a) => { +// return Result::Ok(f(a)) +// } +// Result::Err(e) => { +// return Result::Err(e) +// } +// } +// } +// } + + + +// fn main() { +// let r = foo() +// r.map(|t| ...) +// } + + +// enum Result1 + +// Result<_, E> + +// Flip (Result) + + + +// ((+) `foldl` 0) [1..5] +// ((`foldl` 0) [1..5]) (+) + +// flip :: (a -> b -> c) -> b -> a -> c +// f :: a -> b -> c -> d -> e +// flip f :: b -> a -> c -> d -> e diff --git a/library/core/src/ctrl/monad/option.fe b/library/core/src/ctrl/monad/option.fe new file mode 100644 index 0000000000..68227e89c7 --- /dev/null +++ b/library/core/src/ctrl/monad/option.fe @@ -0,0 +1,13 @@ +use ingot::ctrl::{monad::Monad, function::Fn} +use ingot::data::{option::Option, tuple::Tuple} + +impl Monad for Option { + fn bind(self: Self, morph: Morph) -> Self + where Morph: Fn<(Source), Self, 1>, (Source): Tuple<1> + { + match self { + Self::Some(self) => morph.exec(args: (self, )) + Self::None => Self::None + } + } +} diff --git a/library/core/src/data.fe b/library/core/src/data.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/core/src/data/list.fe b/library/core/src/data/list.fe new file mode 100644 index 0000000000..ff7bc3519a --- /dev/null +++ b/library/core/src/data/list.fe @@ -0,0 +1,4 @@ +trait List { + fn list_get(self, index: N) -> Value + fn list_set(mut self, index: N, value: Value) +} \ No newline at end of file diff --git a/library/core/src/data/map.fe b/library/core/src/data/map.fe new file mode 100644 index 0000000000..37f24b7b3e --- /dev/null +++ b/library/core/src/data/map.fe @@ -0,0 +1,4 @@ +trait Map { + fn map_get(self, key: Key) -> Value + fn map_set(mut self, key: Key, value: Value) +} \ No newline at end of file diff --git a/library/core/src/data/option.fe b/library/core/src/data/option.fe new file mode 100644 index 0000000000..b6b588295b --- /dev/null +++ b/library/core/src/data/option.fe @@ -0,0 +1,4 @@ +pub enum Option { + Some(Value), + None +} \ No newline at end of file diff --git a/library/core/src/data/result.fe b/library/core/src/data/result.fe new file mode 100644 index 0000000000..9e69fcea09 --- /dev/null +++ b/library/core/src/data/result.fe @@ -0,0 +1,4 @@ +pub enum Result { + Ok(Ok), + Err(Err), +} \ No newline at end of file diff --git a/library/core/src/data/set.fe b/library/core/src/data/set.fe new file mode 100644 index 0000000000..7479800a81 --- /dev/null +++ b/library/core/src/data/set.fe @@ -0,0 +1,3 @@ +pub trait Set { + +} \ No newline at end of file diff --git a/library/core/src/data/string.fe b/library/core/src/data/string.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/core/src/data/tuple.fe b/library/core/src/data/tuple.fe new file mode 100644 index 0000000000..1fed8896fc --- /dev/null +++ b/library/core/src/data/tuple.fe @@ -0,0 +1 @@ +pub trait Tuple { } \ No newline at end of file diff --git a/library/core/src/io.fe b/library/core/src/io.fe new file mode 100644 index 0000000000..1af0440761 --- /dev/null +++ b/library/core/src/io.fe @@ -0,0 +1,15 @@ +trait Read { + fn read(self) -> Out +} + +trait Write { + fn write(mut self, value: In) +} + +trait Encode> { + fn encode(mut self, mut w: W) +} + +trait Decode> { + fn decode(mut self, mut r: R) -> Self +} \ No newline at end of file diff --git a/library/core/src/lib.fe b/library/core/src/lib.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/core/src/num.fe b/library/core/src/num.fe new file mode 100644 index 0000000000..1d75fe8fea --- /dev/null +++ b/library/core/src/num.fe @@ -0,0 +1,25 @@ +use self::arith::{Add, Sub, Mul, Div, Neg, Mod, Pow} +use ingot::ctrl::monad::Monad + +pub trait Num: Add + Sub + Mul + Div + Pow { } + +pub trait Complex: Num + Neg { + fn re() -> N + fn im() -> N +} + +pub trait Real: Num + Neg { } + +pub trait Frac: Num + Neg { + fn nu() -> N + fn de() -> N +} + +pub trait Int: Num + Mod + Neg { } + +pub trait Nat: Num + Mod { } + +// impl *> Num for M +// where M: Monad, N: Num { } + +impl Num for u8 { } \ No newline at end of file diff --git a/library/core/src/num/arith.fe b/library/core/src/num/arith.fe new file mode 100644 index 0000000000..2b4b5b2fd2 --- /dev/null +++ b/library/core/src/num/arith.fe @@ -0,0 +1,78 @@ +/// Addition (e.g. `x + y`) +pub trait HAdd { + fn add(self, rhs: Rhs) -> Out +} + +/// Subtraction (e.g. `x - y`) +pub trait HSub { + fn sub(self, rhs: Rhs) -> Out +} + +/// Multiplication (e.g. `x * y`) +pub trait HMul { + fn mul(self, rhs: Rhs) -> Out +} + +/// Division (e.g. `x / y`) +pub trait HDiv { + fn div(self, rhs: Rhs) -> Out +} + +/// Modulo (e.g. `x % y`) +pub trait HMod { + fn modulo(self, rhs: Rhs) -> Out +} + +/// Power (e.g. `x ** y`) +pub trait HPow { + fn pow(self, rhs: Rhs) -> Out +} + +/// Neg (e.g. `-x`) +pub trait HNeg { + fn neg(self) -> Out +} + +pub trait Add: HAdd { } + +pub trait Sub: HSub { } + +pub trait Mul: HMul { } + +pub trait Div: HDiv { } + +pub trait Pow: HPow { } + +pub trait Mod: HMod { } + +pub trait Neg: HNeg { } + +struct BindAdd { n: N } + +impl HAdd for i8 { fn add(self, rhs: Self) -> Self { self + rhs } } +impl HSub for i8 { fn sub(self, rhs: Self) -> Self { self - rhs } } +impl HMul for i8 { fn mul(self, rhs: Self) -> Self { self * rhs } } +impl HDiv for i8 { fn div(self, rhs: Self) -> Self { self / rhs } } +impl HPow for i8 { fn pow(self, rhs: Self) -> Self { self ** rhs } } +impl HNeg for i8 { fn neg(self) -> Self { -self } } + +impl Add for i8 { } +impl Sub for i8 { } +impl Mul for i8 { } +impl Div for i8 { } +impl Pow for i8 { } +impl Neg for i8 { } + +impl HAdd for u8 { fn add(self, rhs: Self) -> Self { self + rhs } } +impl HSub for u8 { fn sub(self, rhs: Self) -> Self { self - rhs } } +impl HMul for u8 { fn mul(self, rhs: Self) -> Self { self * rhs } } +impl HDiv for u8 { fn div(self, rhs: Self) -> Self { self / rhs } } +impl HPow for u8 { fn pow(self, rhs: Self) -> Self { self ** rhs } } +impl HNeg for u8 { fn neg(self) -> Self { -self } } + +impl Add for u8 { } +impl Sub for u8 { } +impl Mul for u8 { } +impl Div for u8 { } +impl Pow for u8 { } +impl Neg for u8 { } diff --git a/library/core/src/num/nat.fe b/library/core/src/num/nat.fe new file mode 100644 index 0000000000..03656fe059 --- /dev/null +++ b/library/core/src/num/nat.fe @@ -0,0 +1,15 @@ +// impl *, N> Fn<1, (N), M> for BindAdd +// where M: Monad, N: HAdd, (N): Tuple<1> +// { +// fn exec(self, args: (N)) -> M { +// M::pure(t: args.0.add(rhs: self.n)) +// } +// } + +// impl *, N> HAdd> for M +// where M: Monad, N: HAdd, (N): Tuple<1> +// { +// fn add(self, rhs: N) -> M { +// self.bind>(morph: BindAdd { n: rhs }) +// } +// } diff --git a/library/eth/fe.toml b/library/eth/fe.toml new file mode 100644 index 0000000000..7576ea1108 --- /dev/null +++ b/library/eth/fe.toml @@ -0,0 +1,3 @@ +[package] +name = "eth" +version = "1.0.0" \ No newline at end of file diff --git a/library/eth/src/abi.fe b/library/eth/src/abi.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/eth/src/contract.fe b/library/eth/src/contract.fe new file mode 100644 index 0000000000..ef342faaae --- /dev/null +++ b/library/eth/src/contract.fe @@ -0,0 +1,18 @@ +trait Contract { + fn init(buf: CallBuffer) -> Self + fn recv(self, buf: CallBuffer) -> MemBuffer +} + +struct Foo { + f1: u8, + f2: bool, + f3: Data +} + +impl Contract for Foo { + fn init(buf: CallBuffer) -> Self { + let f1 = buf.read() + let f2 = buf.read() + Self { f1, f2, } + } +} \ No newline at end of file diff --git a/library/eth/src/lib.fe b/library/eth/src/lib.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/std/fe.toml b/library/std/fe.toml new file mode 100644 index 0000000000..3cbc2c2783 --- /dev/null +++ b/library/std/fe.toml @@ -0,0 +1,3 @@ +[package] +name = "std" +version = "1.0.0" \ No newline at end of file diff --git a/library/std/src/data/list.fe b/library/std/src/data/list.fe new file mode 100644 index 0000000000..fe85b02494 --- /dev/null +++ b/library/std/src/data/list.fe @@ -0,0 +1 @@ +// use ingot::target::evm::{alloc} \ No newline at end of file diff --git a/library/std/src/lib.fe b/library/std/src/lib.fe new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/std/src/target/evm.fe b/library/std/src/target/evm.fe new file mode 100644 index 0000000000..8421e445bc --- /dev/null +++ b/library/std/src/target/evm.fe @@ -0,0 +1,10 @@ +// struct MemBuf { +// fn read() -> +// fn write() +// } + +// extern { +// alloc(size: usize) -> ??????? +// } + + From 6bbb4af56b5ece1f1b532693b9d05c825a69f8a6 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Mon, 2 Sep 2024 22:03:15 -0600 Subject: [PATCH 2/7] hacking --- Cargo.lock | 21 +++--- crates/common2/Cargo.toml | 3 + crates/common2/src/config.rs | 37 ++++++++++ crates/common2/src/input.rs | 2 +- crates/common2/src/lib.rs | 2 + crates/common2/src/resolver.rs | 11 +++ crates/common2/src/resolver/fs.rs | 53 ++++++++++++++ crates/common2/src/resolver/git.rs | 90 +++++++++++++++++++++++ crates/common2/src/resolver/ingot.rs | 67 +++++++++++++++++ crates/driver2/Cargo.toml | 4 +- crates/driver2/src/check.rs | 105 +++++++++------------------ crates/driver2/src/lib.rs | 1 + crates/driver2/src/main.rs | 96 +++++++++++------------- 13 files changed, 352 insertions(+), 140 deletions(-) create mode 100644 crates/common2/src/config.rs create mode 100644 crates/common2/src/resolver.rs create mode 100644 crates/common2/src/resolver/fs.rs create mode 100644 crates/common2/src/resolver/git.rs create mode 100644 crates/common2/src/resolver/ingot.rs diff --git a/Cargo.lock b/Cargo.lock index f8d27d68d2..9f44444832 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1091,10 +1091,13 @@ version = "0.26.0" dependencies = [ "camino", "fe-parser2", + "git2", "indexmap 2.2.6", "salsa 0.18.0", "semver 1.0.23", + "serde", "smol_str", + "toml 0.8.15", ] [[package]] @@ -1188,8 +1191,6 @@ dependencies = [ "include_dir", "salsa 0.18.0", "semver 1.0.23", - "serde", - "toml 0.8.14", "walkdir", ] @@ -3471,14 +3472,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.14", + "toml_edit 0.22.16", ] [[package]] @@ -3516,15 +3517,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.9", + "winnow 0.6.15", ] [[package]] @@ -3997,9 +3998,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.9" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" dependencies = [ "memchr", ] diff --git a/crates/common2/Cargo.toml b/crates/common2/Cargo.toml index a81984c0b2..9331a70adc 100644 --- a/crates/common2/Cargo.toml +++ b/crates/common2/Cargo.toml @@ -16,3 +16,6 @@ smol_str = "0.1.24" salsa = { git = "https://github.com/salsa-rs/salsa", rev = "a1bf3a6" } indexmap = "2.2" parser = { path = "../parser2", package = "fe-parser2" } +toml = "0.8.13" +serde = { version = "1", features = ["derive"] } +git2 = "0.18.3" diff --git a/crates/common2/src/config.rs b/crates/common2/src/config.rs new file mode 100644 index 0000000000..8ceef72963 --- /dev/null +++ b/crates/common2/src/config.rs @@ -0,0 +1,37 @@ +// use camino::Utf8PathBuf; +// use indexmap::IndexSet; +// use serde::{Deserialize, Serialize}; +// use toml::Table; + +// use crate::resolver::ingot::IngotDesc; + +// #[derive(Deserialize, Serialize)] +// pub struct Config { +// pub modes: Table, +// pub base_registry: Table, +// } + +// impl Config { +// pub fn new() -> Self { +// Self { +// base_registry: Table::new(), +// } +// } + +// pub fn base_registry(&self) -> IndexSet { +// self.base_registry +// .iter() +// .map(|(name, value)| IngotDesc::from(name, value)) +// .collect() +// } +// } + +// pub fn load_config(path: Utf8PathBuf) -> Config { +// let text = std::fs::read_to_string(path).unwrap(); +// toml::from_str(&text).unwrap() +// } + +// pub fn write_config(path: Utf8PathBuf, config: Config) { +// let text = toml::to_string(&config).unwrap(); +// std::fs::write(path, text).unwrap(); +// } diff --git a/crates/common2/src/input.rs b/crates/common2/src/input.rs index 5bdd8dc8e3..5b568599b3 100644 --- a/crates/common2/src/input.rs +++ b/crates/common2/src/input.rs @@ -60,7 +60,7 @@ impl InputIngot { } /// Set the list of files which the ingot contains. - /// All files must bee set before the ingot is used. + /// All files must be set before the ingot is used. pub fn set_files(self, db: &mut dyn InputDb, files: IndexSet) { self.__set_files_impl(db).to(files); } diff --git a/crates/common2/src/lib.rs b/crates/common2/src/lib.rs index f6cb0fab67..87ff4cc650 100644 --- a/crates/common2/src/lib.rs +++ b/crates/common2/src/lib.rs @@ -1,6 +1,8 @@ +pub mod config; pub mod diagnostics; pub mod indexmap; pub mod input; +pub mod resolver; pub use input::{InputFile, InputIngot}; diff --git a/crates/common2/src/resolver.rs b/crates/common2/src/resolver.rs new file mode 100644 index 0000000000..416aea036f --- /dev/null +++ b/crates/common2/src/resolver.rs @@ -0,0 +1,11 @@ +pub mod fs; +pub mod git; +pub mod ingot; + +pub trait Resolver { + type ResourceDesc; + type Resource; + type ResolutionError; + + fn resolve(&self, id: &Self::ResourceDesc) -> Result; +} diff --git a/crates/common2/src/resolver/fs.rs b/crates/common2/src/resolver/fs.rs new file mode 100644 index 0000000000..7e7df0ebdd --- /dev/null +++ b/crates/common2/src/resolver/fs.rs @@ -0,0 +1,53 @@ +use camino::Utf8PathBuf; +use serde::Deserialize; + +use super::Resolver; + +#[derive(Deserialize)] +pub struct DirPath { + pub path: String, +} + +pub struct DirReader { + path: Utf8PathBuf, +} + +pub struct LazyDirResolver; + +impl Resolver for LazyDirResolver { + type ResourceDesc = DirPath; + type Resource = DirReader; + type ResolutionError = String; + + fn resolve(&self, desc: &DirPath) -> Result { + if let Ok(path) = Utf8PathBuf::try_from(desc.path.clone()) { + if !path.exists() { + Err("Path does not exist".to_string()) + } else { + Ok(DirReader { path }) + } + } else { + Err("Invalid path".to_string()) + } + } +} + +// fn collect_file_paths( +// path: &Utf8PathBuf, +// files: &mut IndexSet, +// ) -> std::io::Result<()> { +// if path.is_dir() { +// for entry in path.read_dir()? { +// let entry = entry?; +// let path = Utf8PathBuf::from_path_buf(entry.path()) +// .expect("could not covert PathBuf to Utf8PathBuf"); + +// if path.is_dir() { +// collect_file_paths(&path, files)?; +// } else { +// files.insert(path); +// } +// } +// } +// Ok(()) +// } diff --git a/crates/common2/src/resolver/git.rs b/crates/common2/src/resolver/git.rs new file mode 100644 index 0000000000..80c33dc4a1 --- /dev/null +++ b/crates/common2/src/resolver/git.rs @@ -0,0 +1,90 @@ +use camino::Utf8PathBuf; +use serde::Deserialize; + +use super::Resolver; + +#[derive(Deserialize)] +pub struct GitRepoDesc { + remote: String, + refspec: String, + local_path: Option, +} + +pub struct GitRepo { + repo: git2::Repository, +} + +pub struct GitResolver { + pub default_clone_path: Utf8PathBuf, +} + +// pub enum GitResolutionError { +// GitResolutionError(()), +// FsResolutionError(std::io::Error), +// } + +impl Resolver for GitResolver { + type ResourceDesc = GitRepoDesc; + type Resource = GitRepo; + type ResolutionError = String; + + fn resolve(&self, desc: &GitRepoDesc) -> Result { + todo!("") + } +} + +// use git2::{FetchOptions, Oid, Repository}; +// use std::error::Error; +// use std::path::Path; + +// /// Fetch and checkout the specified refspec from the remote repository without +// /// fetching any additional history. +// pub fn fetch_and_checkout>( +// remote: &str, +// target_directory: P, +// refspec: &str, +// ) -> Result<(), Box> { +// // We initialize the repo here so that we can be sure that we created a directory that +// // needs to be clean up in case of an error. If the init fails, there won't be anything +// // to clean up. +// let repo = Repository::init(&target_directory)?; +// let res = _fetch_and_checkout(remote, repo, refspec); +// if res.is_err() { +// std::fs::remove_dir_all(target_directory).expect("Failed to clean up directory"); +// } + +// res +// } + +// fn _fetch_and_checkout( +// remote: &str, +// repo: Repository, +// refspec: &str, +// ) -> Result<(), Box> { +// let mut remote = repo.remote("origin", remote)?; + +// let mut fetch_options = FetchOptions::new(); + +// fetch_options.depth(1); + +// // Fetch the specified SHA1 with depth 1 +// if let Err(e) = remote.fetch(&[refspec], Some(&mut fetch_options), None) { +// if let (git2::ErrorClass::Net, git2::ErrorCode::GenericError) = (e.class(), e.code()) { +// // That's a pretty cryptic error for the common case of the refspec not existing. +// // We keep the cryptic error (because it might have other causes) but add a hint. +// return Err(format!("{}\nMake sure revision {} exists in remote", e, refspec).into()); +// } else { +// return Err(e.into()); +// } +// } + +// // Find the fetched commit by SHA1 +// let oid = Oid::from_str(refspec)?; +// let commit = repo.find_commit(oid)?; + +// // Checkout the commit +// repo.checkout_tree(commit.as_object(), None)?; +// repo.set_head_detached(oid)?; + +// Ok(()) +// } diff --git a/crates/common2/src/resolver/ingot.rs b/crates/common2/src/resolver/ingot.rs new file mode 100644 index 0000000000..3096b4a6df --- /dev/null +++ b/crates/common2/src/resolver/ingot.rs @@ -0,0 +1,67 @@ +use std::marker::PhantomData; + +use camino::Utf8PathBuf; +use indexmap::IndexSet; +use semver::Version; +use serde::Deserialize; +use smol_str::SmolStr; +use toml::Table; + +use super::{fs::LazyDirResolver, git::GitResolver, Resolver}; + +#[derive(Deserialize)] +pub struct IngotDesc { + name: SmolStr, + version: String, + #[serde(flatten)] + files_desc: FD, +} + +#[derive(Deserialize)] +pub struct Config { + pub name: SmolStr, + pub version: SmolStr, + dependencies: Table, +} + +impl Config { + fn dependencies(&self) -> IndexSet> { + todo!("dependency") + } +} + +trait IngotFiles { + fn config(&self) -> Config; + fn src(&self) -> IndexSet<(Utf8PathBuf, Vec)>; + fn root_path(&self) -> Utf8PathBuf; +} + +pub struct Ingot +where + F: IngotFiles, +{ + desc_name: SmolStr, + desc_version: Version, + files: F, +} + +pub struct IngotResolver { + files_resolver: FR, +} + +pub type FsIngotResolver = IngotResolver; +pub type GitIngotResolver = IngotResolver; + +impl Resolver for IngotResolver +where + FR: Resolver, + FR::Resource: IngotFiles, +{ + type ResourceDesc = IngotDesc; + type Resource = Ingot; + type ResolutionError = (); + + fn resolve(&self, desc: &IngotDesc) -> Result, ()> { + Err(()) + } +} diff --git a/crates/driver2/Cargo.toml b/crates/driver2/Cargo.toml index f60fbeb22d..609deeadc6 100644 --- a/crates/driver2/Cargo.toml +++ b/crates/driver2/Cargo.toml @@ -18,9 +18,7 @@ common = { path = "../common2", package = "fe-common2" } hir-analysis = { path = "../hir-analysis", package = "fe-hir-analysis" } camino = "1.1.4" clap = { version = "4.3", features = ["derive"] } -toml = "0.8.13" -serde = { version = "1", features = ["derive"] } semver = "1.0.23" walkdir = "2" include_dir = "0.7" -dirs = "5.0.1" \ No newline at end of file +dirs = "5.0.1" diff --git a/crates/driver2/src/check.rs b/crates/driver2/src/check.rs index eaaff90638..bd404beb82 100644 --- a/crates/driver2/src/check.rs +++ b/crates/driver2/src/check.rs @@ -6,79 +6,9 @@ use fe_driver2::DriverDataBase; use include_dir::{include_dir, Dir}; use semver::Version; use std::fs; -use std::path::PathBuf; use std::{collections::BTreeSet, path::Path}; -const STD_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../library/std"); - -fn write_std_files(std_path: &Path) { - write_files_recursive(&STD_DIR, std_path); -} - -fn write_files_recursive(dir: &Dir<'_>, base_path: &Path) { - for file in dir.files() { - let file_path = base_path.join(file.path()); - if let Some(parent_dir) = file_path.parent() { - std::fs::create_dir_all(parent_dir).unwrap(); - } - std::fs::write(file_path, file.contents()).unwrap(); - } - - for subdir in dir.dirs() { - let subdir_path = base_path.join(subdir.path()); - std::fs::create_dir_all(&subdir_path).unwrap(); - write_files_recursive(subdir, &base_path); - } -} - -pub fn run_check(args: &CheckArgs) { - let std_path = match &args.std_path { - Some(path) => PathBuf::from(path.to_owned()), - None => { - let home_dir = dirs::home_dir().expect("Failed to get user home directory"); - home_dir.join(".fe/std") - } - }; - if !std_path.exists() { - println!("The standard library is not installed. Do you want to perform the write? (y/n)"); - let mut input = String::new(); - std::io::stdin().read_line(&mut input).unwrap(); - let input = input.trim().to_lowercase(); - if input == "y" || input == "yes" { - write_std_files(&std_path); - } else { - eprintln!( - "Cannot perform the write without the standard library being installed on disk" - ); - std::process::exit(2); - } - } - - let path = Path::new(&args.path); - if !path.exists() { - eprintln!("Path '{}' does not exist", path.display()); - std::process::exit(2); - } - - let mut db = DriverDataBase::default(); - - let std_ingot = load_ingot(&std_path, &mut db, IngotKind::Std, &mut IndexSet::default()); - - if path.is_file() { - let source = fs::read_to_string(path).unwrap(); - check_single_file(path, source, std_ingot, &mut db, args.dump_scope_graph); - } else if path.is_dir() { - check_ingot(path, std_ingot, &mut db, args.dump_scope_graph); - } else { - eprintln!( - "Path '{}' is neither a file nor a directory", - path.display() - ); - std::process::exit(2); - } -} - -pub fn check_single_file( +pub fn check_standalone( path: &Path, source: String, std_ingot: InputIngot, @@ -143,3 +73,36 @@ pub fn check_ingot( // println!("{}", dump_scope_graph(db, top_mod)); // } } + +use include_dir::{include_dir, Dir}; +use std::path::PathBuf; +use std::{collections::BTreeSet, path::Path}; + +fn check_std_lib_exists(std_lib_files: &Dir, std_lib_path: &Path) -> bool { + true +} + +fn write_std_lib(std_lib_files: &Dir, std_lib_path: &Path) { + write_files_recursive(std_lib_files, std_lib_path); +} + +fn default_std_lib_path() -> PathBuf { + let home_dir = dirs::home_dir().expect("Failed to get user home directory"); + home_dir.join(".fe/std") +} + +fn write_files_recursive(dir: &Dir<'_>, base_path: &Path) { + for file in dir.files() { + let file_path = base_path.join(file.path()); + if let Some(parent_dir) = file_path.parent() { + std::fs::create_dir_all(parent_dir).unwrap(); + } + std::fs::write(file_path, file.contents()).unwrap(); + } + + for subdir in dir.dirs() { + let subdir_path = base_path.join(subdir.path()); + std::fs::create_dir_all(&subdir_path).unwrap(); + write_files_recursive(subdir, &base_path); + } +} diff --git a/crates/driver2/src/lib.rs b/crates/driver2/src/lib.rs index c8824937f8..2027afa4ec 100644 --- a/crates/driver2/src/lib.rs +++ b/crates/driver2/src/lib.rs @@ -1,4 +1,5 @@ pub mod diagnostics; +pub mod fs; use std::path; diff --git a/crates/driver2/src/main.rs b/crates/driver2/src/main.rs index 113ca9972d..e2e095b0e9 100644 --- a/crates/driver2/src/main.rs +++ b/crates/driver2/src/main.rs @@ -71,63 +71,49 @@ pub fn main() { // String::from_utf8(s).unwrap() // } -fn load_ingot( - path: &Path, - db: &mut dyn InputDb, - ingot_kind: IngotKind, - dependencies: &mut IndexSet, -) -> InputIngot { - let manifest_path = path.join("fe.toml"); - let manifest_content = - std::fs::read_to_string(&manifest_path).expect("Unable to read manifest file"); - let manifest: Manifest = toml::from_str(&manifest_content).expect("Invalid TOML format"); - - let project_name = &manifest.package.name; - let project_version = &manifest.package.version; - - let version = Version::parse(project_version).expect("Invalid version format"); - - let ingot = InputIngot::new( - db, - path.to_str().unwrap(), - ingot_kind, - version, - IndexSet::default(), - ); - - if let Some(deps) = &manifest.dependencies { - for dep in deps { - let dep_path = path.join(dep); - let dep_ingot = load_ingot(&dep_path, db, IngotKind::External, dependencies); - dependencies.insert(IngotDependency::new(dep, dep_ingot)); +fn run_check(args: &CheckArgs) { + let std_path = match &args.std_path { + Some(path) => PathBuf::from(path.to_owned()), + None => { + let home_dir = dirs::home_dir().expect("Failed to get user home directory"); + home_dir.join(".fe/std") + } + }; + if !std_path.exists() { + println!("The standard library is not installed. Do you want to perform the write? (y/n)"); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let input = input.trim().to_lowercase(); + if input == "y" || input == "yes" { + write_std_files(&std_path); + } else { + eprintln!( + "Cannot perform the write without the standard library being installed on disk" + ); + std::process::exit(2); } } - let src_path = path.join("src"); - set_src_files(&src_path, db, ingot); - - ingot -} + let path = Path::new(&args.path); + if !path.exists() { + eprintln!("Path '{}' does not exist", path.display()); + std::process::exit(2); + } -fn set_src_files(path: &Path, db: &mut dyn InputDb, ingot: InputIngot) { - let input_files: IndexSet<_> = WalkDir::new(path) - .into_iter() - // .expect("read_dir call failed") - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.path().is_file()) - .map(|entry| { - let file_path = entry.path().to_str().unwrap().to_owned(); - let content = std::fs::read_to_string(&file_path).unwrap(); - InputFile::new(db, ingot, file_path.into(), content) - }) - .collect(); - - let root_file = input_files - .iter() - .find(|file| file.path(db).ends_with("lib.fe")) - .expect("Root file 'lib.fe' not found") - .clone(); - - ingot.set_root_file(db, root_file); - ingot.set_files(db, input_files); + let mut db = DriverDataBase::default(); + + let std_ingot = load_ingot(&std_path, &mut db, IngotKind::Std, &mut IndexSet::default()); + + if path.is_file() { + let source = fs::read_to_string(path).unwrap(); + check_single_file(path, source, std_ingot, &mut db, args.dump_scope_graph); + } else if path.is_dir() { + check_ingot(path, std_ingot, &mut db, args.dump_scope_graph); + } else { + eprintln!( + "Path '{}' is neither a file nor a directory", + path.display() + ); + std::process::exit(2); + } } From 020a9e38204164b995abe57ead9bad825a340ab6 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Wed, 4 Sep 2024 18:38:37 -0600 Subject: [PATCH 3/7] hacking --- crates/common2/src/resolver.rs | 3 +- crates/common2/src/resolver/fs.rs | 8 ++- crates/common2/src/resolver/ingot.rs | 25 +++++--- crates/driver2/src/lib.rs | 1 - crates/driver2/src/main.rs | 92 ++++++++++++++-------------- 5 files changed, 70 insertions(+), 59 deletions(-) diff --git a/crates/common2/src/resolver.rs b/crates/common2/src/resolver.rs index 416aea036f..6be304c619 100644 --- a/crates/common2/src/resolver.rs +++ b/crates/common2/src/resolver.rs @@ -3,9 +3,10 @@ pub mod git; pub mod ingot; pub trait Resolver { + type Config; type ResourceDesc; type Resource; type ResolutionError; - fn resolve(&self, id: &Self::ResourceDesc) -> Result; + fn resolve(&self, desc: &Self::ResourceDesc) -> Result; } diff --git a/crates/common2/src/resolver/fs.rs b/crates/common2/src/resolver/fs.rs index 7e7df0ebdd..5bec1c35d8 100644 --- a/crates/common2/src/resolver/fs.rs +++ b/crates/common2/src/resolver/fs.rs @@ -8,12 +8,14 @@ pub struct DirPath { pub path: String, } -pub struct DirReader { +// pub struct DirReader { +// path: Utf8PathBuf, +// } + +pub struct LazyDirResolver { path: Utf8PathBuf, } -pub struct LazyDirResolver; - impl Resolver for LazyDirResolver { type ResourceDesc = DirPath; type Resource = DirReader; diff --git a/crates/common2/src/resolver/ingot.rs b/crates/common2/src/resolver/ingot.rs index 3096b4a6df..5f97cc3b33 100644 --- a/crates/common2/src/resolver/ingot.rs +++ b/crates/common2/src/resolver/ingot.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use camino::Utf8PathBuf; use indexmap::IndexSet; use semver::Version; @@ -11,8 +9,8 @@ use super::{fs::LazyDirResolver, git::GitResolver, Resolver}; #[derive(Deserialize)] pub struct IngotDesc { - name: SmolStr, - version: String, + // name: SmolStr, + version: Option, #[serde(flatten)] files_desc: FD, } @@ -31,7 +29,7 @@ impl Config { } trait IngotFiles { - fn config(&self) -> Config; + fn config(&self) -> Filestate; fn src(&self) -> IndexSet<(Utf8PathBuf, Vec)>; fn root_path(&self) -> Utf8PathBuf; } @@ -40,17 +38,28 @@ pub struct Ingot where F: IngotFiles, { - desc_name: SmolStr, + // desc_name: SmolStr, desc_version: Version, files: F, } +impl Ingot +where + F: IngotFiles, +{ + pub fn src_files(&self) -> IngotDesc { + self.files.root_path() + } +} + pub struct IngotResolver { files_resolver: FR, + diagnostics: (), } -pub type FsIngotResolver = IngotResolver; -pub type GitIngotResolver = IngotResolver; +pub type IngotFsResolver = IngotResolver; +// my_dep = { version = "1.0.0", path = "path/to/dep" } +pub type IngotGitResolver = IngotResolver; impl Resolver for IngotResolver where diff --git a/crates/driver2/src/lib.rs b/crates/driver2/src/lib.rs index 2027afa4ec..c8824937f8 100644 --- a/crates/driver2/src/lib.rs +++ b/crates/driver2/src/lib.rs @@ -1,5 +1,4 @@ pub mod diagnostics; -pub mod fs; use std::path; diff --git a/crates/driver2/src/main.rs b/crates/driver2/src/main.rs index e2e095b0e9..b66991908d 100644 --- a/crates/driver2/src/main.rs +++ b/crates/driver2/src/main.rs @@ -71,49 +71,49 @@ pub fn main() { // String::from_utf8(s).unwrap() // } -fn run_check(args: &CheckArgs) { - let std_path = match &args.std_path { - Some(path) => PathBuf::from(path.to_owned()), - None => { - let home_dir = dirs::home_dir().expect("Failed to get user home directory"); - home_dir.join(".fe/std") - } - }; - if !std_path.exists() { - println!("The standard library is not installed. Do you want to perform the write? (y/n)"); - let mut input = String::new(); - std::io::stdin().read_line(&mut input).unwrap(); - let input = input.trim().to_lowercase(); - if input == "y" || input == "yes" { - write_std_files(&std_path); - } else { - eprintln!( - "Cannot perform the write without the standard library being installed on disk" - ); - std::process::exit(2); - } - } - - let path = Path::new(&args.path); - if !path.exists() { - eprintln!("Path '{}' does not exist", path.display()); - std::process::exit(2); - } - - let mut db = DriverDataBase::default(); - - let std_ingot = load_ingot(&std_path, &mut db, IngotKind::Std, &mut IndexSet::default()); - - if path.is_file() { - let source = fs::read_to_string(path).unwrap(); - check_single_file(path, source, std_ingot, &mut db, args.dump_scope_graph); - } else if path.is_dir() { - check_ingot(path, std_ingot, &mut db, args.dump_scope_graph); - } else { - eprintln!( - "Path '{}' is neither a file nor a directory", - path.display() - ); - std::process::exit(2); - } -} +// fn run_check(args: &CheckArgs) { +// let std_path = match &args.std_path { +// Some(path) => PathBuf::from(path.to_owned()), +// None => { +// let home_dir = dirs::home_dir().expect("Failed to get user home directory"); +// home_dir.join(".fe/std") +// } +// }; +// if !std_path.exists() { +// println!("The standard library is not installed. Do you want to perform the write? (y/n)"); +// let mut input = String::new(); +// std::io::stdin().read_line(&mut input).unwrap(); +// let input = input.trim().to_lowercase(); +// if input == "y" || input == "yes" { +// write_std_files(&std_path); +// } else { +// eprintln!( +// "Cannot perform the write without the standard library being installed on disk" +// ); +// std::process::exit(2); +// } +// } + +// let path = Path::new(&args.path); +// if !path.exists() { +// eprintln!("Path '{}' does not exist", path.display()); +// std::process::exit(2); +// } + +// let mut db = DriverDataBase::default(); + +// let std_ingot = load_ingot(&std_path, &mut db, IngotKind::Std, &mut IndexSet::default()); + +// if path.is_file() { +// let source = fs::read_to_string(path).unwrap(); +// check_single_file(path, source, std_ingot, &mut db, args.dump_scope_graph); +// } else if path.is_dir() { +// check_ingot(path, std_ingot, &mut db, args.dump_scope_graph); +// } else { +// eprintln!( +// "Path '{}' is neither a file nor a directory", +// path.display() +// ); +// std::process::exit(2); +// } +// } From 806c02c1fd94c74ac578b7920fb2a55d3e5c5eb7 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Thu, 12 Sep 2024 10:48:59 -0600 Subject: [PATCH 4/7] hacking --- Cargo.lock | 19 ++++- crates/common2/src/resolver/fs.rs | 55 -------------- crates/common2/src/resolver/ingot.rs | 76 ------------------- crates/resolver/Cargo.toml | 17 +++++ crates/resolver/src/files.rs | 38 ++++++++++ .../resolver => resolver/src/files}/git.rs | 32 ++++---- crates/resolver/src/files/local.rs | 39 ++++++++++ crates/resolver/src/ingot.rs | 17 +++++ crates/resolver/src/ingot/config.rs | 41 ++++++++++ crates/resolver/src/ingot/src_files.rs | 36 +++++++++ .../src/resolver.rs => resolver/src/lib.rs} | 4 +- 11 files changed, 224 insertions(+), 150 deletions(-) delete mode 100644 crates/common2/src/resolver/fs.rs delete mode 100644 crates/common2/src/resolver/ingot.rs create mode 100644 crates/resolver/Cargo.toml create mode 100644 crates/resolver/src/files.rs rename crates/{common2/src/resolver => resolver/src/files}/git.rs (76%) create mode 100644 crates/resolver/src/files/local.rs create mode 100644 crates/resolver/src/ingot.rs create mode 100644 crates/resolver/src/ingot/config.rs create mode 100644 crates/resolver/src/ingot/src_files.rs rename crates/{common2/src/resolver.rs => resolver/src/lib.rs} (77%) diff --git a/Cargo.lock b/Cargo.lock index 9f44444832..2207559f5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1301,6 +1301,19 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "fe-resolver" +version = "0.26.0" +dependencies = [ + "camino", + "git2", + "indexmap 2.2.6", + "semver 1.0.23", + "serde", + "smol_str", + "toml 0.8.15", +] + [[package]] name = "fe-test-files" version = "0.26.0" @@ -3525,7 +3538,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.15", + "winnow 0.6.18", ] [[package]] @@ -3998,9 +4011,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] diff --git a/crates/common2/src/resolver/fs.rs b/crates/common2/src/resolver/fs.rs deleted file mode 100644 index 5bec1c35d8..0000000000 --- a/crates/common2/src/resolver/fs.rs +++ /dev/null @@ -1,55 +0,0 @@ -use camino::Utf8PathBuf; -use serde::Deserialize; - -use super::Resolver; - -#[derive(Deserialize)] -pub struct DirPath { - pub path: String, -} - -// pub struct DirReader { -// path: Utf8PathBuf, -// } - -pub struct LazyDirResolver { - path: Utf8PathBuf, -} - -impl Resolver for LazyDirResolver { - type ResourceDesc = DirPath; - type Resource = DirReader; - type ResolutionError = String; - - fn resolve(&self, desc: &DirPath) -> Result { - if let Ok(path) = Utf8PathBuf::try_from(desc.path.clone()) { - if !path.exists() { - Err("Path does not exist".to_string()) - } else { - Ok(DirReader { path }) - } - } else { - Err("Invalid path".to_string()) - } - } -} - -// fn collect_file_paths( -// path: &Utf8PathBuf, -// files: &mut IndexSet, -// ) -> std::io::Result<()> { -// if path.is_dir() { -// for entry in path.read_dir()? { -// let entry = entry?; -// let path = Utf8PathBuf::from_path_buf(entry.path()) -// .expect("could not covert PathBuf to Utf8PathBuf"); - -// if path.is_dir() { -// collect_file_paths(&path, files)?; -// } else { -// files.insert(path); -// } -// } -// } -// Ok(()) -// } diff --git a/crates/common2/src/resolver/ingot.rs b/crates/common2/src/resolver/ingot.rs deleted file mode 100644 index 5f97cc3b33..0000000000 --- a/crates/common2/src/resolver/ingot.rs +++ /dev/null @@ -1,76 +0,0 @@ -use camino::Utf8PathBuf; -use indexmap::IndexSet; -use semver::Version; -use serde::Deserialize; -use smol_str::SmolStr; -use toml::Table; - -use super::{fs::LazyDirResolver, git::GitResolver, Resolver}; - -#[derive(Deserialize)] -pub struct IngotDesc { - // name: SmolStr, - version: Option, - #[serde(flatten)] - files_desc: FD, -} - -#[derive(Deserialize)] -pub struct Config { - pub name: SmolStr, - pub version: SmolStr, - dependencies: Table, -} - -impl Config { - fn dependencies(&self) -> IndexSet> { - todo!("dependency") - } -} - -trait IngotFiles { - fn config(&self) -> Filestate; - fn src(&self) -> IndexSet<(Utf8PathBuf, Vec)>; - fn root_path(&self) -> Utf8PathBuf; -} - -pub struct Ingot -where - F: IngotFiles, -{ - // desc_name: SmolStr, - desc_version: Version, - files: F, -} - -impl Ingot -where - F: IngotFiles, -{ - pub fn src_files(&self) -> IngotDesc { - self.files.root_path() - } -} - -pub struct IngotResolver { - files_resolver: FR, - diagnostics: (), -} - -pub type IngotFsResolver = IngotResolver; -// my_dep = { version = "1.0.0", path = "path/to/dep" } -pub type IngotGitResolver = IngotResolver; - -impl Resolver for IngotResolver -where - FR: Resolver, - FR::Resource: IngotFiles, -{ - type ResourceDesc = IngotDesc; - type Resource = Ingot; - type ResolutionError = (); - - fn resolve(&self, desc: &IngotDesc) -> Result, ()> { - Err(()) - } -} diff --git a/crates/resolver/Cargo.toml b/crates/resolver/Cargo.toml new file mode 100644 index 0000000000..0e4d5586a3 --- /dev/null +++ b/crates/resolver/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "fe-resolver" +version = "0.26.0" +authors = ["The Fe Developers "] +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/ethereum/fe" +description = "Resolver lib for Fe." + +[dependencies] +semver = "1.0.17" +camino = "1.1.4" +smol_str = "0.1.24" +toml = "0.8.13" +serde = { version = "1", features = ["derive"] } +git2 = "0.18.3" +indexmap = "2.2" diff --git a/crates/resolver/src/files.rs b/crates/resolver/src/files.rs new file mode 100644 index 0000000000..d09c56d448 --- /dev/null +++ b/crates/resolver/src/files.rs @@ -0,0 +1,38 @@ +use camino::Utf8PathBuf; +use git::GitDesc; +use local::LocalDesc; +use serde::Deserialize; + +use crate::Resolver; + +mod git; +mod local; + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum AnyFilesDesc { + Local(LocalDesc), + Git(GitDesc), +} + +pub struct AnyFilesResolver; + +pub enum AnyFilesResolutionError { + Local(local::LocalResolutionError), + Git(git::GitResolutionError), +} + +impl Resolver for AnyFilesResolver { + type Config = (); + type ResourceDesc = AnyFilesDesc; + type Resource = Utf8PathBuf; + type ResolutionError = AnyFilesResolutionError; + + fn from_config(config: &Self::Config) -> Self { + todo!() + } + + fn resolve(&self, desc: &AnyFilesDesc) -> Result { + todo!() + } +} diff --git a/crates/common2/src/resolver/git.rs b/crates/resolver/src/files/git.rs similarity index 76% rename from crates/common2/src/resolver/git.rs rename to crates/resolver/src/files/git.rs index 80c33dc4a1..134d4ee06f 100644 --- a/crates/common2/src/resolver/git.rs +++ b/crates/resolver/src/files/git.rs @@ -1,34 +1,38 @@ use camino::Utf8PathBuf; use serde::Deserialize; -use super::Resolver; +use crate::Resolver; #[derive(Deserialize)] -pub struct GitRepoDesc { +pub struct GitDesc { remote: String, refspec: String, local_path: Option, } -pub struct GitRepo { - repo: git2::Repository, -} - pub struct GitResolver { pub default_clone_path: Utf8PathBuf, } -// pub enum GitResolutionError { -// GitResolutionError(()), -// FsResolutionError(std::io::Error), -// } +pub struct GitResolutionError; impl Resolver for GitResolver { - type ResourceDesc = GitRepoDesc; - type Resource = GitRepo; - type ResolutionError = String; + type Config = (); + type ResourceDesc = GitDesc; + type Resource = Utf8PathBuf; + type ResolutionError = GitResolutionError; + + fn from_config(_: &Self::Config) -> Self { + todo!("") + } - fn resolve(&self, desc: &GitRepoDesc) -> Result { + fn resolve(&self, desc: &GitDesc) -> Result { + // check to see if the dep is already in the dep directory + // check to see if the repo is already cached on the local fs + // if it is, then check to see if the repo is valid with respect to the CID or refspec + // if the repo is not cached, clone it + // copy to dep directory + // resolve the repo path todo!("") } } diff --git a/crates/resolver/src/files/local.rs b/crates/resolver/src/files/local.rs new file mode 100644 index 0000000000..f8576c4843 --- /dev/null +++ b/crates/resolver/src/files/local.rs @@ -0,0 +1,39 @@ +use camino::Utf8PathBuf; +use serde::Deserialize; + +use super::Resolver; + +#[derive(Deserialize)] +pub struct LocalDesc { + pub path: String, +} + +pub struct LocalResolver; + +pub enum LocalResolutionError { + Invalid, + DoesNotExist, +} + +impl Resolver for LocalResolver { + type Config = (); + type ResourceDesc = LocalDesc; + type Resource = Utf8PathBuf; + type ResolutionError = LocalResolutionError; + + fn from_config(config: &Self::Config) -> Self { + todo!() + } + + fn resolve(&self, desc: &LocalDesc) -> Result { + if let Ok(path) = Utf8PathBuf::try_from(desc.path.clone()) { + if !path.exists() { + Err(LocalResolutionError::DoesNotExist) + } else { + Ok(path) + } + } else { + Err(LocalResolutionError::Invalid) + } + } +} diff --git a/crates/resolver/src/ingot.rs b/crates/resolver/src/ingot.rs new file mode 100644 index 0000000000..b7c4417a6c --- /dev/null +++ b/crates/resolver/src/ingot.rs @@ -0,0 +1,17 @@ +use serde::Deserialize; +use smol_str::SmolStr; + +use crate::files::AnyFilesDesc; + +mod config; +mod src_files; + +#[derive(Deserialize)] +pub struct IngotDesc { + name: SmolStr, + version: Option, + #[serde(flatten)] + files_desc: FD, +} + +pub type AnyIngotDesc = IngotDesc; diff --git a/crates/resolver/src/ingot/config.rs b/crates/resolver/src/ingot/config.rs new file mode 100644 index 0000000000..6ad8c8d3bd --- /dev/null +++ b/crates/resolver/src/ingot/config.rs @@ -0,0 +1,41 @@ +use smol_str::SmolStr; + +use crate::Resolver; + +use super::IngotDesc; + +pub struct Config { + pub name: SmolStr, + pub version: SmolStr, + dependencies: Vec>, +} + +pub struct ConfigResolutionError; + +pub struct ConfigResolver { + files_resolver: FR, +} + +impl Resolver for ConfigResolver +where + FR: Resolver, +{ + type Config = (); + type ResourceDesc = IngotDesc; + type Resource = Config; + type ResolutionError = ConfigResolutionError; + + fn from_config(config: &Self::Config) -> Self { + todo!() + } + + fn resolve( + &self, + desc: &IngotDesc, + ) -> Result, ConfigResolutionError> { + // load the config file data + // parse the toml + // check toml content (version, features, etc) + // + } +} diff --git a/crates/resolver/src/ingot/src_files.rs b/crates/resolver/src/ingot/src_files.rs new file mode 100644 index 0000000000..458e8883ae --- /dev/null +++ b/crates/resolver/src/ingot/src_files.rs @@ -0,0 +1,36 @@ +use camino::Utf8PathBuf; +use indexmap::IndexSet; + +use crate::Resolver; + +use super::IngotDesc; + +pub struct SrcFilesResolver { + files_resolver: FR, +} + +pub enum SrcFilesResolutionError { + MissingDirectory, + MissingRootFile, +} + +impl Resolver for SrcFilesResolver +where + FR: Resolver, +{ + type Config = (); + type ResourceDesc = IngotDesc; + type Resource = IndexSet; + type ResolutionError = SrcFilesResolutionError; + + fn from_config(config: &Self::Config) -> Self { + todo!() + } + + fn resolve( + &self, + desc: &IngotDesc, + ) -> Result, SrcFilesResolutionError> { + todo!() + } +} diff --git a/crates/common2/src/resolver.rs b/crates/resolver/src/lib.rs similarity index 77% rename from crates/common2/src/resolver.rs rename to crates/resolver/src/lib.rs index 6be304c619..4660eb3778 100644 --- a/crates/common2/src/resolver.rs +++ b/crates/resolver/src/lib.rs @@ -1,5 +1,4 @@ -pub mod fs; -pub mod git; +pub mod files; pub mod ingot; pub trait Resolver { @@ -8,5 +7,6 @@ pub trait Resolver { type Resource; type ResolutionError; + fn from_config(config: &Self::Config) -> Self; fn resolve(&self, desc: &Self::ResourceDesc) -> Result; } From 0c2a16b12f6fb1ea469ad8e97a6a0a860a90dfc0 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Mon, 23 Sep 2024 23:22:44 -0600 Subject: [PATCH 5/7] hacking --- crates/resolver/Cargo.toml | 1 + crates/resolver/src/files.rs | 10 +- crates/resolver/src/files/git.rs | 152 ++++++++++++++----------- crates/resolver/src/files/local.rs | 12 +- crates/resolver/src/ingot.rs | 14 ++- crates/resolver/src/ingot/config.rs | 57 ++++++++-- crates/resolver/src/ingot/dep_graph.rs | 71 ++++++++++++ crates/resolver/src/ingot/src_files.rs | 70 +++++++++--- 8 files changed, 285 insertions(+), 102 deletions(-) create mode 100644 crates/resolver/src/ingot/dep_graph.rs diff --git a/crates/resolver/Cargo.toml b/crates/resolver/Cargo.toml index 0e4d5586a3..7512bf179b 100644 --- a/crates/resolver/Cargo.toml +++ b/crates/resolver/Cargo.toml @@ -15,3 +15,4 @@ toml = "0.8.13" serde = { version = "1", features = ["derive"] } git2 = "0.18.3" indexmap = "2.2" +petgraph = "0.5.1" diff --git a/crates/resolver/src/files.rs b/crates/resolver/src/files.rs index d09c56d448..9fd914b38f 100644 --- a/crates/resolver/src/files.rs +++ b/crates/resolver/src/files.rs @@ -1,6 +1,6 @@ use camino::Utf8PathBuf; -use git::GitDesc; -use local::LocalDesc; +use git::{GitDesc, GitResolutionError}; +use local::{LocalDesc, LocalResolutionError}; use serde::Deserialize; use crate::Resolver; @@ -8,7 +8,7 @@ use crate::Resolver; mod git; mod local; -#[derive(Deserialize)] +#[derive(Deserialize, Hash, Debug)] #[serde(untagged)] pub enum AnyFilesDesc { Local(LocalDesc), @@ -18,8 +18,8 @@ pub enum AnyFilesDesc { pub struct AnyFilesResolver; pub enum AnyFilesResolutionError { - Local(local::LocalResolutionError), - Git(git::GitResolutionError), + Local(LocalResolutionError), + Git(GitResolutionError), } impl Resolver for AnyFilesResolver { diff --git a/crates/resolver/src/files/git.rs b/crates/resolver/src/files/git.rs index 134d4ee06f..dae0b412ef 100644 --- a/crates/resolver/src/files/git.rs +++ b/crates/resolver/src/files/git.rs @@ -1,9 +1,11 @@ use camino::Utf8PathBuf; +use git2::{Error as Git2Error, FetchOptions, Oid, Repository}; use serde::Deserialize; +use std::fs; use crate::Resolver; -#[derive(Deserialize)] +#[derive(Deserialize, Hash, Debug, Clone)] pub struct GitDesc { remote: String, refspec: String, @@ -14,7 +16,34 @@ pub struct GitResolver { pub default_clone_path: Utf8PathBuf, } -pub struct GitResolutionError; +#[derive(Debug)] +pub enum GitResolutionError { + GitError(Git2Error), + IoError(std::io::Error), + InvalidOid, +} + +impl From for GitResolutionError { + fn from(error: Git2Error) -> Self { + GitResolutionError::GitError(error) + } +} + +impl From for GitResolutionError { + fn from(error: std::io::Error) -> Self { + GitResolutionError::IoError(error) + } +} + +impl std::fmt::Display for GitResolutionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + GitResolutionError::GitError(e) => write!(f, "Git error: {}", e), + GitResolutionError::IoError(e) => write!(f, "IO error: {}", e), + GitResolutionError::InvalidOid => write!(f, "Invalid OID for refspec"), + } + } +} impl Resolver for GitResolver { type Config = (); @@ -23,72 +52,65 @@ impl Resolver for GitResolver { type ResolutionError = GitResolutionError; fn from_config(_: &Self::Config) -> Self { - todo!("") + todo!() } fn resolve(&self, desc: &GitDesc) -> Result { - // check to see if the dep is already in the dep directory - // check to see if the repo is already cached on the local fs - // if it is, then check to see if the repo is valid with respect to the CID or refspec - // if the repo is not cached, clone it - // copy to dep directory - // resolve the repo path - todo!("") + let clone_path = if let Some(ref local_path) = desc.local_path { + Utf8PathBuf::from(local_path) + } else { + self.default_clone_path + .join(format!("{}_{}", &desc.remote, &desc.refspec)) + }; + + if clone_path.exists() { + let repo = Repository::open(&clone_path).map_err(GitResolutionError::from)?; + + if !repo.find_reference(&desc.refspec).is_ok() { + fs::remove_dir_all(&clone_path)?; + self.clone_repo(&desc.remote, &clone_path, &desc.refspec)?; + } + } else { + self.clone_repo(&desc.remote, &clone_path, &desc.refspec)?; + } + + Ok(clone_path) } } -// use git2::{FetchOptions, Oid, Repository}; -// use std::error::Error; -// use std::path::Path; - -// /// Fetch and checkout the specified refspec from the remote repository without -// /// fetching any additional history. -// pub fn fetch_and_checkout>( -// remote: &str, -// target_directory: P, -// refspec: &str, -// ) -> Result<(), Box> { -// // We initialize the repo here so that we can be sure that we created a directory that -// // needs to be clean up in case of an error. If the init fails, there won't be anything -// // to clean up. -// let repo = Repository::init(&target_directory)?; -// let res = _fetch_and_checkout(remote, repo, refspec); -// if res.is_err() { -// std::fs::remove_dir_all(target_directory).expect("Failed to clean up directory"); -// } - -// res -// } - -// fn _fetch_and_checkout( -// remote: &str, -// repo: Repository, -// refspec: &str, -// ) -> Result<(), Box> { -// let mut remote = repo.remote("origin", remote)?; - -// let mut fetch_options = FetchOptions::new(); - -// fetch_options.depth(1); - -// // Fetch the specified SHA1 with depth 1 -// if let Err(e) = remote.fetch(&[refspec], Some(&mut fetch_options), None) { -// if let (git2::ErrorClass::Net, git2::ErrorCode::GenericError) = (e.class(), e.code()) { -// // That's a pretty cryptic error for the common case of the refspec not existing. -// // We keep the cryptic error (because it might have other causes) but add a hint. -// return Err(format!("{}\nMake sure revision {} exists in remote", e, refspec).into()); -// } else { -// return Err(e.into()); -// } -// } - -// // Find the fetched commit by SHA1 -// let oid = Oid::from_str(refspec)?; -// let commit = repo.find_commit(oid)?; - -// // Checkout the commit -// repo.checkout_tree(commit.as_object(), None)?; -// repo.set_head_detached(oid)?; - -// Ok(()) -// } +impl GitResolver { + fn clone_repo( + &self, + remote: &str, + target_directory: &Utf8PathBuf, + refspec: &str, + ) -> Result<(), GitResolutionError> { + let repo = Repository::init(target_directory)?; + + self.fetch_and_checkout(remote, &repo, refspec)?; + + Ok(()) + } + + fn fetch_and_checkout( + &self, + remote: &str, + repo: &Repository, + refspec: &str, + ) -> Result<(), GitResolutionError> { + let mut remote = repo.remote("origin", remote)?; + + let mut fetch_options = FetchOptions::new(); + fetch_options.depth(1); + + remote.fetch(&[refspec], Some(&mut fetch_options), None)?; + + let oid = Oid::from_str(refspec).map_err(|_| GitResolutionError::InvalidOid)?; + let commit = repo.find_commit(oid)?; + + repo.checkout_tree(commit.as_object(), None)?; + repo.set_head_detached(oid)?; + + Ok(()) + } +} diff --git a/crates/resolver/src/files/local.rs b/crates/resolver/src/files/local.rs index f8576c4843..cc8239a3c3 100644 --- a/crates/resolver/src/files/local.rs +++ b/crates/resolver/src/files/local.rs @@ -3,7 +3,7 @@ use serde::Deserialize; use super::Resolver; -#[derive(Deserialize)] +#[derive(Deserialize, Hash, Debug)] pub struct LocalDesc { pub path: String, } @@ -11,8 +11,8 @@ pub struct LocalDesc { pub struct LocalResolver; pub enum LocalResolutionError { - Invalid, - DoesNotExist, + InvalidPath, + PathDoesNotExist, } impl Resolver for LocalResolver { @@ -21,19 +21,19 @@ impl Resolver for LocalResolver { type Resource = Utf8PathBuf; type ResolutionError = LocalResolutionError; - fn from_config(config: &Self::Config) -> Self { + fn from_config(_: &Self::Config) -> Self { todo!() } fn resolve(&self, desc: &LocalDesc) -> Result { if let Ok(path) = Utf8PathBuf::try_from(desc.path.clone()) { if !path.exists() { - Err(LocalResolutionError::DoesNotExist) + Err(LocalResolutionError::PathDoesNotExist) } else { Ok(path) } } else { - Err(LocalResolutionError::Invalid) + Err(LocalResolutionError::InvalidPath) } } } diff --git a/crates/resolver/src/ingot.rs b/crates/resolver/src/ingot.rs index b7c4417a6c..6b474808f1 100644 --- a/crates/resolver/src/ingot.rs +++ b/crates/resolver/src/ingot.rs @@ -1,17 +1,21 @@ use serde::Deserialize; use smol_str::SmolStr; +use std::hash::Hash; use crate::files::AnyFilesDesc; mod config; +mod dep_graph; mod src_files; -#[derive(Deserialize)] -pub struct IngotDesc { - name: SmolStr, - version: Option, +#[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct IngotDesc +where + FD: Hash, +{ + pub version: Option, #[serde(flatten)] - files_desc: FD, + pub files_desc: FD, } pub type AnyIngotDesc = IngotDesc; diff --git a/crates/resolver/src/ingot/config.rs b/crates/resolver/src/ingot/config.rs index 6ad8c8d3bd..0bce558565 100644 --- a/crates/resolver/src/ingot/config.rs +++ b/crates/resolver/src/ingot/config.rs @@ -1,16 +1,32 @@ +use camino::Utf8PathBuf; +use serde::de::DeserializeOwned; +use serde::Deserialize; use smol_str::SmolStr; +use std::hash::Hash; +use std::{collections::HashMap, fs}; +use toml; use crate::Resolver; use super::IngotDesc; -pub struct Config { +#[derive(Deserialize)] +pub struct Config +where + FD: Hash, +{ pub name: SmolStr, pub version: SmolStr, - dependencies: Vec>, + pub dependencies: HashMap>, } -pub struct ConfigResolutionError; +#[derive(Debug)] +pub enum ConfigResolutionError { + FileNotFound, + FileReadError(std::io::Error), + TomlParseError(toml::de::Error), + InvalidConfig(String), +} pub struct ConfigResolver { files_resolver: FR, @@ -19,13 +35,16 @@ pub struct ConfigResolver { impl Resolver for ConfigResolver where FR: Resolver, + FR::ResourceDesc: Hash, + FR::Resource: AsRef, + Config: DeserializeOwned, { type Config = (); type ResourceDesc = IngotDesc; type Resource = Config; type ResolutionError = ConfigResolutionError; - fn from_config(config: &Self::Config) -> Self { + fn from_config(_config: &Self::Config) -> Self { todo!() } @@ -33,9 +52,31 @@ where &self, desc: &IngotDesc, ) -> Result, ConfigResolutionError> { - // load the config file data - // parse the toml - // check toml content (version, features, etc) - // + let config_path = self + .files_resolver + .resolve(&desc.files_desc) + .map_err(|_| ConfigResolutionError::FileNotFound)? + .as_ref() + .join("fe.toml"); + + let file_content = + fs::read_to_string(&config_path).map_err(ConfigResolutionError::FileReadError)?; + + let config: Config = + toml::from_str(&file_content).map_err(ConfigResolutionError::TomlParseError)?; + + if config.name.is_empty() { + return Err(ConfigResolutionError::InvalidConfig( + "Invalid configuration: 'name' field is missing or empty.".to_string(), + )); + } + + if config.version.is_empty() { + return Err(ConfigResolutionError::InvalidConfig( + "Invalid configuration: 'version' field is missing or empty.".to_string(), + )); + } + + Ok(config) } } diff --git a/crates/resolver/src/ingot/dep_graph.rs b/crates/resolver/src/ingot/dep_graph.rs new file mode 100644 index 0000000000..9b29f51048 --- /dev/null +++ b/crates/resolver/src/ingot/dep_graph.rs @@ -0,0 +1,71 @@ +use std::fmt::Debug; +use std::hash::Hash; + +use crate::Resolver; +use indexmap::{IndexMap, IndexSet}; +use petgraph::graph::{DiGraph, NodeIndex}; +use serde::de::DeserializeOwned; + +use super::config::ConfigResolver; +use super::IngotDesc; + +#[derive(Debug)] +struct DepGraphResolutionError; + +struct DepGraph +where + FD: Hash, +{ + graph: DiGraph, ()>, + node_map: IndexMap, NodeIndex>, +} + +struct DepGraphResolver { + config_resolver: ConfigResolver, +} + +impl Resolver for DepGraphResolver +where + FR: Resolver, + FR::ResourceDesc: Hash + Clone + Eq + Debug, + FR::Resource: DeserializeOwned, +{ + type Config = (); + type ResourceDesc = IngotDesc; + type Resource = DepGraph; + type ResolutionError = DepGraphResolutionError; + + fn from_config(_config: &Self::Config) -> Self { + todo!() + } + + fn resolve(&self, desc: &Self::ResourceDesc) -> Result { + let mut graph = DiGraph::new(); + let mut node_map = IndexMap::new(); + let mut visited = IndexSet::new(); + let mut stack = vec![desc.clone()]; + + while let Some(current_desc) = stack.pop() { + if visited.contains(¤t_desc) { + continue; + } + + visited.insert(current_desc.clone()); + + let current_node = node_map + .entry(current_desc.clone()) + .or_insert_with(|| graph.add_node(current_desc.clone())); + + let current_config = self + .config_resolver + .resolve(¤t_desc) + .map_err(|_| DepGraphResolutionError)?; + + for (name, desc) in current_config.dependencies { + stack.push(desc); + } + } + + Ok(DepGraph { graph, node_map }) + } +} diff --git a/crates/resolver/src/ingot/src_files.rs b/crates/resolver/src/ingot/src_files.rs index 458e8883ae..a7cc1e211e 100644 --- a/crates/resolver/src/ingot/src_files.rs +++ b/crates/resolver/src/ingot/src_files.rs @@ -1,36 +1,80 @@ -use camino::Utf8PathBuf; -use indexmap::IndexSet; - +use super::IngotDesc; use crate::Resolver; +use camino::Utf8PathBuf; +use indexmap::IndexMap; +use std::fs; +use std::hash::Hash; +use std::io; -use super::IngotDesc; +#[derive(Debug)] +pub enum SrcFilesResolutionError { + FileNotFound, + DirectoryNotFound, + FileReadError(io::Error), +} pub struct SrcFilesResolver { files_resolver: FR, } -pub enum SrcFilesResolutionError { - MissingDirectory, - MissingRootFile, -} - impl Resolver for SrcFilesResolver where FR: Resolver, + FR::ResourceDesc: Hash, + FR::Resource: AsRef, { type Config = (); type ResourceDesc = IngotDesc; - type Resource = IndexSet; + type Resource = IndexMap>; type ResolutionError = SrcFilesResolutionError; - fn from_config(config: &Self::Config) -> Self { + fn from_config(_config: &Self::Config) -> Self { todo!() } fn resolve( &self, desc: &IngotDesc, - ) -> Result, SrcFilesResolutionError> { - todo!() + ) -> Result>, SrcFilesResolutionError> { + let src_dir = self + .files_resolver + .resolve(&desc.files_desc) + .map_err(|_| SrcFilesResolutionError::FileNotFound)? + .as_ref() + .join("src"); + + if !src_dir.exists() || !src_dir.is_dir() { + return Err(SrcFilesResolutionError::DirectoryNotFound); + } + + let mut file_map = IndexMap::new(); + + collect_files_and_contents(&src_dir, &mut file_map)?; + + Ok(file_map) } } + +fn collect_files_and_contents( + dir: &Utf8PathBuf, + file_map: &mut IndexMap>, +) -> Result<(), SrcFilesResolutionError> { + for entry in fs::read_dir(dir).map_err(SrcFilesResolutionError::FileReadError)? { + let entry = entry.map_err(SrcFilesResolutionError::FileReadError)?; + let path = Utf8PathBuf::from_path_buf(entry.path()).map_err(|_| { + SrcFilesResolutionError::FileReadError(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid UTF-8 path", + )) + })?; + + if path.is_dir() { + collect_files_and_contents(&path, file_map)?; + } else if path.is_file() { + let content = fs::read(&path).map_err(SrcFilesResolutionError::FileReadError)?; + file_map.insert(path, content); + } + } + + Ok(()) +} From c391a7392c2225cde51003c744a2e2fa6d2269ff Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Mon, 16 Dec 2024 13:43:14 -0700 Subject: [PATCH 6/7] hacking --- Cargo.lock | 22 +- crates/common2/src/input.rs | 3 + crates/common2/src/lib.rs | 1 - crates/driver2/Cargo.toml | 1 + crates/driver2/src/lib.rs | 52 ++++- crates/resolver/src/files.rs | 38 ---- crates/resolver/src/files/local.rs | 39 ---- crates/resolver/src/ingot.rs | 43 +++- crates/resolver/src/ingot/config.rs | 56 ++--- crates/resolver/src/ingot/dep_graph.rs | 71 ------ crates/resolver/src/ingot/dependencies.rs | 210 ++++++++++++++++++ crates/resolver/src/ingot/src_files.rs | 35 +-- crates/resolver/src/lib.rs | 12 +- crates/resolver/src/path.rs | 25 +++ .../resolver/src/{files/git.rs => remote.rs} | 23 +- crates/resolver/test_files/A/config.toml | 6 + crates/resolver/test_files/B/config.toml | 5 + crates/resolver/test_files/C/config.toml | 5 + crates/resolver/test_files/D/config.toml | 2 + 19 files changed, 405 insertions(+), 244 deletions(-) delete mode 100644 crates/resolver/src/files.rs delete mode 100644 crates/resolver/src/files/local.rs delete mode 100644 crates/resolver/src/ingot/dep_graph.rs create mode 100644 crates/resolver/src/ingot/dependencies.rs create mode 100644 crates/resolver/src/path.rs rename crates/resolver/src/{files/git.rs => remote.rs} (87%) create mode 100644 crates/resolver/test_files/A/config.toml create mode 100644 crates/resolver/test_files/B/config.toml create mode 100644 crates/resolver/test_files/C/config.toml create mode 100644 crates/resolver/test_files/D/config.toml diff --git a/Cargo.lock b/Cargo.lock index 2207559f5b..cf5c6eff85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1033,7 +1033,7 @@ dependencies = [ "num-bigint", "num-traits", "parking_lot_core 0.8.0", - "petgraph", + "petgraph 0.6.5", "pretty_assertions", "rstest", "salsa 0.16.1", @@ -1188,6 +1188,7 @@ dependencies = [ "fe-common2", "fe-hir", "fe-hir-analysis", + "fe-resolver", "include_dir", "salsa 0.18.0", "semver 1.0.23", @@ -1308,6 +1309,7 @@ dependencies = [ "camino", "git2", "indexmap 2.2.6", + "petgraph 0.5.1", "semver 1.0.23", "serde", "smol_str", @@ -1367,6 +1369,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -2336,13 +2344,23 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset 0.2.0", + "indexmap 1.9.3", +] + [[package]] name = "petgraph" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ - "fixedbitset", + "fixedbitset 0.4.2", "indexmap 2.2.6", ] diff --git a/crates/common2/src/input.rs b/crates/common2/src/input.rs index 5b568599b3..5d67e0222c 100644 --- a/crates/common2/src/input.rs +++ b/crates/common2/src/input.rs @@ -105,6 +105,9 @@ pub enum IngotKind { /// Standard library ingot. Std, + + /// Core library ingot. + Core, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/common2/src/lib.rs b/crates/common2/src/lib.rs index 87ff4cc650..be8441ea93 100644 --- a/crates/common2/src/lib.rs +++ b/crates/common2/src/lib.rs @@ -2,7 +2,6 @@ pub mod config; pub mod diagnostics; pub mod indexmap; pub mod input; -pub mod resolver; pub use input::{InputFile, InputIngot}; diff --git a/crates/driver2/Cargo.toml b/crates/driver2/Cargo.toml index 609deeadc6..09c160c8a6 100644 --- a/crates/driver2/Cargo.toml +++ b/crates/driver2/Cargo.toml @@ -16,6 +16,7 @@ codespan-reporting = "0.11" hir = { path = "../hir", package = "fe-hir" } common = { path = "../common2", package = "fe-common2" } hir-analysis = { path = "../hir-analysis", package = "fe-hir-analysis" } +resolver = { path = "../resolver", package = "fe-resolver" } camino = "1.1.4" clap = { version = "4.3", features = ["derive"] } semver = "1.0.23" diff --git a/crates/driver2/src/lib.rs b/crates/driver2/src/lib.rs index c8824937f8..91a6f90401 100644 --- a/crates/driver2/src/lib.rs +++ b/crates/driver2/src/lib.rs @@ -2,14 +2,15 @@ pub mod diagnostics; use std::path; +use camino::Utf8PathBuf; use codespan_reporting::term::{ self, termcolor::{BufferWriter, ColorChoice}, }; use common::{ diagnostics::CompleteDiagnostic, - indexmap::IndexSet, - input::{IngotKind, Version}, + indexmap::{IndexMap, IndexSet}, + input::{IngotDependency, IngotKind, Version}, InputDb, InputFile, InputIngot, }; use hir::{ @@ -27,6 +28,12 @@ use hir_analysis::{ }, HirAnalysisDb, }; +use resolver::{ + ingot::{ + config::ConfigResolver, dependencies::DependenciesResolver, src_files::SrcFilesResolver, + }, + Resolver, +}; use crate::diagnostics::ToCsDiag; @@ -91,6 +98,47 @@ impl DriverDataBase { DiagnosticsCollection(pass_manager.run_on_module_tree(tree)) } + pub fn ingot(&mut self, ingot_path: &path::Path) -> InputIngot { + let config_resolver = ConfigResolver; + let dep_resolver = DependenciesResolver { config_resolver }; + let src_files_resolver = SrcFilesResolver; + + let dep_graph = dep_resolver.resolve(ingot_path).unwrap(); + + let input_ingots = IndexMap::new(); + + for path in dep_graph.reverse_toposort() { + let ingot_kind = if path == ingot_path { + IngotKind::Local + } else { + IngotKind::External + }; + let external_ingots = + dep_graph + .dependencies(&dep) + .iter() + .map(|(name, _, path)| IngotDependency { + name, + ingot: input_ingots[path], + }); + input_ingot[ingot_path] = + InputIngot::new(self, path, ingot_kind, version, external_ingots); + } + + for (ingot_path, input_ingot) in input_ingots { + let files = src_files_resolver.resolve(&ingot_path); + let input_files = files + .into_iter() + .map(|(path, content)| InputFile::new(self, input_ingot, file_path, content)) + .collect(); + input_ingot.set_files(db, input_files); + // match lib.fe and main.fe + // input_ingot.set_root_file(db, input_files[0]); + } + + input_ingots[ingot_path] + } + pub fn standalone(&mut self, file_path: &path::Path, source: &str) -> InputFile { let kind = IngotKind::StandAlone; diff --git a/crates/resolver/src/files.rs b/crates/resolver/src/files.rs deleted file mode 100644 index 9fd914b38f..0000000000 --- a/crates/resolver/src/files.rs +++ /dev/null @@ -1,38 +0,0 @@ -use camino::Utf8PathBuf; -use git::{GitDesc, GitResolutionError}; -use local::{LocalDesc, LocalResolutionError}; -use serde::Deserialize; - -use crate::Resolver; - -mod git; -mod local; - -#[derive(Deserialize, Hash, Debug)] -#[serde(untagged)] -pub enum AnyFilesDesc { - Local(LocalDesc), - Git(GitDesc), -} - -pub struct AnyFilesResolver; - -pub enum AnyFilesResolutionError { - Local(LocalResolutionError), - Git(GitResolutionError), -} - -impl Resolver for AnyFilesResolver { - type Config = (); - type ResourceDesc = AnyFilesDesc; - type Resource = Utf8PathBuf; - type ResolutionError = AnyFilesResolutionError; - - fn from_config(config: &Self::Config) -> Self { - todo!() - } - - fn resolve(&self, desc: &AnyFilesDesc) -> Result { - todo!() - } -} diff --git a/crates/resolver/src/files/local.rs b/crates/resolver/src/files/local.rs deleted file mode 100644 index cc8239a3c3..0000000000 --- a/crates/resolver/src/files/local.rs +++ /dev/null @@ -1,39 +0,0 @@ -use camino::Utf8PathBuf; -use serde::Deserialize; - -use super::Resolver; - -#[derive(Deserialize, Hash, Debug)] -pub struct LocalDesc { - pub path: String, -} - -pub struct LocalResolver; - -pub enum LocalResolutionError { - InvalidPath, - PathDoesNotExist, -} - -impl Resolver for LocalResolver { - type Config = (); - type ResourceDesc = LocalDesc; - type Resource = Utf8PathBuf; - type ResolutionError = LocalResolutionError; - - fn from_config(_: &Self::Config) -> Self { - todo!() - } - - fn resolve(&self, desc: &LocalDesc) -> Result { - if let Ok(path) = Utf8PathBuf::try_from(desc.path.clone()) { - if !path.exists() { - Err(LocalResolutionError::PathDoesNotExist) - } else { - Ok(path) - } - } else { - Err(LocalResolutionError::InvalidPath) - } - } -} diff --git a/crates/resolver/src/ingot.rs b/crates/resolver/src/ingot.rs index 6b474808f1..1afd01b81b 100644 --- a/crates/resolver/src/ingot.rs +++ b/crates/resolver/src/ingot.rs @@ -2,20 +2,41 @@ use serde::Deserialize; use smol_str::SmolStr; use std::hash::Hash; -use crate::files::AnyFilesDesc; +use crate::{path::PathDescription, remote::GitDescription}; -mod config; -mod dep_graph; -mod src_files; +pub mod config; +pub mod dependencies; +pub mod src_files; -#[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct IngotDesc -where - FD: Hash, -{ +#[derive(Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct IngotDescription { pub version: Option, + // pub fe_version: SmolStr, + // pub features: Vec, #[serde(flatten)] - pub files_desc: FD, + pub files_description: FD, } -pub type AnyIngotDesc = IngotDesc; +#[derive(Deserialize, PartialEq, Debug, Clone, Eq)] +pub enum AnyIngotDescription { + Path(IngotDescription), + Remote(IngotDescription), + Registered(IngotDescription<()>), +} + +// pub struct IngotPathResolver; + +// pub enum IngotPathResolutionError { +// RemotePathOutOfScope, +// LocalPathDoesNotExist, +// } + +// impl Resolver for IngotPathResolver { +// type ResourceDesc = Vec; +// type Resource = Utf8PathBuf; +// type ResolutionError = IngotPathResolutionError; + +// fn resolve(&self, desc: &Self::ResourceDesc) -> Result { +// todo!() +// } +// } diff --git a/crates/resolver/src/ingot/config.rs b/crates/resolver/src/ingot/config.rs index 0bce558565..1bb9b41003 100644 --- a/crates/resolver/src/ingot/config.rs +++ b/crates/resolver/src/ingot/config.rs @@ -1,68 +1,48 @@ use camino::Utf8PathBuf; -use serde::de::DeserializeOwned; use serde::Deserialize; use smol_str::SmolStr; -use std::hash::Hash; use std::{collections::HashMap, fs}; use toml; use crate::Resolver; -use super::IngotDesc; +use super::AnyIngotDescription; -#[derive(Deserialize)] -pub struct Config -where - FD: Hash, -{ +#[derive(Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct Config { pub name: SmolStr, pub version: SmolStr, - pub dependencies: HashMap>, + pub dependencies: HashMap, +} + +pub enum InvalidConfigError { + MissingVersion, + MissingName, + UnrecognizedField(String), } #[derive(Debug)] pub enum ConfigResolutionError { - FileNotFound, + ConfigNotFound, FileReadError(std::io::Error), TomlParseError(toml::de::Error), InvalidConfig(String), } -pub struct ConfigResolver { - files_resolver: FR, -} +pub struct ConfigResolver; -impl Resolver for ConfigResolver -where - FR: Resolver, - FR::ResourceDesc: Hash, - FR::Resource: AsRef, - Config: DeserializeOwned, -{ - type Config = (); - type ResourceDesc = IngotDesc; - type Resource = Config; +impl Resolver for ConfigResolver { + type Description = Utf8PathBuf; + type Resource = Config; type ResolutionError = ConfigResolutionError; - fn from_config(_config: &Self::Config) -> Self { - todo!() - } - - fn resolve( - &self, - desc: &IngotDesc, - ) -> Result, ConfigResolutionError> { - let config_path = self - .files_resolver - .resolve(&desc.files_desc) - .map_err(|_| ConfigResolutionError::FileNotFound)? - .as_ref() - .join("fe.toml"); + fn resolve(&self, desc: &Utf8PathBuf) -> Result { + let config_path = desc.join("fe.toml"); let file_content = fs::read_to_string(&config_path).map_err(ConfigResolutionError::FileReadError)?; - let config: Config = + let config: Config = toml::from_str(&file_content).map_err(ConfigResolutionError::TomlParseError)?; if config.name.is_empty() { diff --git a/crates/resolver/src/ingot/dep_graph.rs b/crates/resolver/src/ingot/dep_graph.rs deleted file mode 100644 index 9b29f51048..0000000000 --- a/crates/resolver/src/ingot/dep_graph.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::fmt::Debug; -use std::hash::Hash; - -use crate::Resolver; -use indexmap::{IndexMap, IndexSet}; -use petgraph::graph::{DiGraph, NodeIndex}; -use serde::de::DeserializeOwned; - -use super::config::ConfigResolver; -use super::IngotDesc; - -#[derive(Debug)] -struct DepGraphResolutionError; - -struct DepGraph -where - FD: Hash, -{ - graph: DiGraph, ()>, - node_map: IndexMap, NodeIndex>, -} - -struct DepGraphResolver { - config_resolver: ConfigResolver, -} - -impl Resolver for DepGraphResolver -where - FR: Resolver, - FR::ResourceDesc: Hash + Clone + Eq + Debug, - FR::Resource: DeserializeOwned, -{ - type Config = (); - type ResourceDesc = IngotDesc; - type Resource = DepGraph; - type ResolutionError = DepGraphResolutionError; - - fn from_config(_config: &Self::Config) -> Self { - todo!() - } - - fn resolve(&self, desc: &Self::ResourceDesc) -> Result { - let mut graph = DiGraph::new(); - let mut node_map = IndexMap::new(); - let mut visited = IndexSet::new(); - let mut stack = vec![desc.clone()]; - - while let Some(current_desc) = stack.pop() { - if visited.contains(¤t_desc) { - continue; - } - - visited.insert(current_desc.clone()); - - let current_node = node_map - .entry(current_desc.clone()) - .or_insert_with(|| graph.add_node(current_desc.clone())); - - let current_config = self - .config_resolver - .resolve(¤t_desc) - .map_err(|_| DepGraphResolutionError)?; - - for (name, desc) in current_config.dependencies { - stack.push(desc); - } - } - - Ok(DepGraph { graph, node_map }) - } -} diff --git a/crates/resolver/src/ingot/dependencies.rs b/crates/resolver/src/ingot/dependencies.rs new file mode 100644 index 0000000000..a952980f5b --- /dev/null +++ b/crates/resolver/src/ingot/dependencies.rs @@ -0,0 +1,210 @@ +use std::fmt::Debug; + +use crate::path::PathDescription; +use crate::remote::GitDescription; +use crate::Resolver; +use camino::Utf8PathBuf; +use indexmap::IndexMap; +use petgraph::csr::NodeIndex; +use petgraph::graph::DiGraph; +use petgraph::visit::EdgeRef; +use petgraph::Direction; +use smol_str::SmolStr; + +use super::config::{ConfigResolutionError, ConfigResolver}; +use super::AnyIngotDescription; + +#[derive(Debug)] +pub enum DependenciesResolutionError { + RootConfigResolutionError(ConfigResolutionError), +} + +pub struct DependencyGraph { + root_path: Utf8PathBuf, + graph: DiGraph, + nodes: IndexMap, +} + +impl DependencyGraph { + pub fn new(root_path: Utf8PathBuf) -> Self { + // let mut graph = DiGraph::new(); + // let node_idx: NodeIndex = graph.add_node(root_path.clone()); + // let mut nodes: IndexMap = IndexMap::new(); + // nodes.insert(local_path.clone(), node_idx); + + // Self { + // root_path, + // graph, + // nodes, + // } + todo!() + } + + pub fn reverse_toposort(&self) -> Vec { + todo!() + } + + pub fn dependencies( + &self, + path: &Utf8PathBuf, + ) -> IndexMap { + let node = NodeIndex::from(self.nodes[path]); + self.graph + .edges_directed(node, Direction::Outgoing) + .map(|edge| { + let (name, description) = edge.weight(); + ( + name.to_owned(), + ( + description.to_owned(), + self.graph.node_weight(edge.target()).unwrap().to_owned(), + ), + ) + }) + .collect() + } + + pub fn contains(&self, path: &Utf8PathBuf) -> bool { + self.nodes.contains_key(path) + } + + pub fn add_dependency( + &mut self, + name: SmolStr, + description: AnyIngotDescription, + from: Utf8PathBuf, + to: Utf8PathBuf, + ) { + // self.graph.add_edge( + // *self.nodes.get(&from).unwrap(), + // *self.nodes.get(&to).unwrap(), + // (name, description), + // ); + todo!() + } +} + +pub struct DependenciesResolver { + pub config_resolver: ConfigResolver, +} + +#[derive(Clone)] +enum DependencyPath { + Local(Utf8PathBuf, Vec), + Remote(GitDescription, Vec), +} + +impl DependencyPath { + pub fn new_remote(remote_description: GitDescription) -> Self { + Self::Remote(remote_description, vec![]) + } + + pub fn new_local(root_path: Utf8PathBuf) -> Self { + Self::Local(root_path, vec![]) + } + + pub fn join(&mut self, path_description: PathDescription) { + match self { + DependencyPath::Local(_, paths) => paths, + DependencyPath::Remote(_, paths) => paths, + } + .push(path_description); + } + + pub fn fs_path(&self) -> Result { + // match self { + // DependencyPath::Local(_, paths) => paths + // .iter() + // .fold(Utf8PathBuf::new(), |acc, path| acc.join(path)), + // DependencyPath::Remote(git_desc, paths) => paths + // .iter() + // .fold(Utf8PathBuf::new(), |acc, path| acc.join(path)), + // } + todo!() + } +} + +struct UnresolvedDependency { + name: SmolStr, + ingot_description: AnyIngotDescription, + source: (Utf8PathBuf, DependencyPath), +} + +impl Resolver for DependenciesResolver { + type Description = Utf8PathBuf; + type Resource = DependencyGraph; + type ResolutionError = DependenciesResolutionError; + + fn resolve( + &self, + description: &Utf8PathBuf, + ) -> Result { + let root_config = self + .config_resolver + .resolve(description) + .map_err(DependenciesResolutionError::RootConfigResolutionError)?; + let mut graph = DependencyGraph::new(description.to_owned()); + let mut unresolved_dependencies = root_config + .dependencies + .into_iter() + .map(|(name, ingot_description)| UnresolvedDependency { + name, + ingot_description, + source: ( + description.clone(), + DependencyPath::new_local(description.clone()), + ), + }) + .collect::>(); + + while let Some(dependency) = unresolved_dependencies.pop() { + let target = match dependency.ingot_description.clone() { + AnyIngotDescription::Path(ingot_description) => { + dependency + .source + .1 + .clone() + .join(ingot_description.files_description); + dependency.source.1 + } + AnyIngotDescription::Remote(ingot_description) => { + DependencyPath::new_remote(ingot_description.files_description) + } + AnyIngotDescription::Registered(_) => todo!(), + }; + let target_path = target.fs_path().unwrap(); + + if !graph.contains(&target_path) { + unresolved_dependencies.append( + &mut self + .config_resolver + .resolve(&target_path) + .unwrap() + .dependencies + .into_iter() + .map(|(name, ingot_description)| UnresolvedDependency { + name, + ingot_description, + source: (target_path.clone(), target.clone()), + }) + .collect::>(), + ) + } + + // add a new edge to the dependency graph + graph.add_dependency( + dependency.name, + dependency.ingot_description, + dependency.source.0, + target_path, + ); + } + + // finally, return the graph with all nodes and edges + Ok(graph) + } +} + +struct DependencyPathResolver { + root_path: Utf8PathBuf, +} diff --git a/crates/resolver/src/ingot/src_files.rs b/crates/resolver/src/ingot/src_files.rs index a7cc1e211e..dfa48a4be5 100644 --- a/crates/resolver/src/ingot/src_files.rs +++ b/crates/resolver/src/ingot/src_files.rs @@ -1,50 +1,31 @@ -use super::IngotDesc; use crate::Resolver; use camino::Utf8PathBuf; use indexmap::IndexMap; use std::fs; -use std::hash::Hash; use std::io; #[derive(Debug)] pub enum SrcFilesResolutionError { - FileNotFound, - DirectoryNotFound, + SrcFolderMissing, + MainFileMissing, FileReadError(io::Error), } -pub struct SrcFilesResolver { - files_resolver: FR, -} +pub struct SrcFilesResolver; -impl Resolver for SrcFilesResolver -where - FR: Resolver, - FR::ResourceDesc: Hash, - FR::Resource: AsRef, -{ - type Config = (); - type ResourceDesc = IngotDesc; +impl Resolver for SrcFilesResolver { + type Description = Utf8PathBuf; type Resource = IndexMap>; type ResolutionError = SrcFilesResolutionError; - fn from_config(_config: &Self::Config) -> Self { - todo!() - } - fn resolve( &self, - desc: &IngotDesc, + desc: &Utf8PathBuf, ) -> Result>, SrcFilesResolutionError> { - let src_dir = self - .files_resolver - .resolve(&desc.files_desc) - .map_err(|_| SrcFilesResolutionError::FileNotFound)? - .as_ref() - .join("src"); + let src_dir = desc.join("src"); if !src_dir.exists() || !src_dir.is_dir() { - return Err(SrcFilesResolutionError::DirectoryNotFound); + return Err(SrcFilesResolutionError::SrcFolderMissing); } let mut file_map = IndexMap::new(); diff --git a/crates/resolver/src/lib.rs b/crates/resolver/src/lib.rs index 4660eb3778..3e73ce2dbf 100644 --- a/crates/resolver/src/lib.rs +++ b/crates/resolver/src/lib.rs @@ -1,12 +1,14 @@ -pub mod files; pub mod ingot; +pub mod path; +pub mod remote; pub trait Resolver { - type Config; - type ResourceDesc; + type Description; type Resource; type ResolutionError; - fn from_config(config: &Self::Config) -> Self; - fn resolve(&self, desc: &Self::ResourceDesc) -> Result; + fn resolve( + &self, + description: &Self::Description, + ) -> Result; } diff --git a/crates/resolver/src/path.rs b/crates/resolver/src/path.rs new file mode 100644 index 0000000000..d1902a0051 --- /dev/null +++ b/crates/resolver/src/path.rs @@ -0,0 +1,25 @@ +use camino::Utf8PathBuf; +use serde::Deserialize; + +use super::Resolver; + +#[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq)] +pub struct PathDescription { + pub path: String, +} + +pub struct PathResolver; + +pub enum PathResolutionError { + AbsolutePathDoesNotExist, +} + +impl Resolver for PathResolver { + type Description = Vec; + type Resource = Utf8PathBuf; + type ResolutionError = PathResolutionError; + + fn resolve(&self, desc: &Vec) -> Result { + todo!() + } +} diff --git a/crates/resolver/src/files/git.rs b/crates/resolver/src/remote.rs similarity index 87% rename from crates/resolver/src/files/git.rs rename to crates/resolver/src/remote.rs index dae0b412ef..69c3032e3d 100644 --- a/crates/resolver/src/files/git.rs +++ b/crates/resolver/src/remote.rs @@ -5,15 +5,23 @@ use std::fs; use crate::Resolver; -#[derive(Deserialize, Hash, Debug, Clone)] -pub struct GitDesc { +#[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq)] +pub struct GitDescription { remote: String, refspec: String, local_path: Option, } pub struct GitResolver { - pub default_clone_path: Utf8PathBuf, + default_clone_path: Utf8PathBuf, +} + +impl Default for GitResolver { + fn default() -> Self { + GitResolver { + default_clone_path: Utf8PathBuf::from(""), + } + } } #[derive(Debug)] @@ -46,16 +54,11 @@ impl std::fmt::Display for GitResolutionError { } impl Resolver for GitResolver { - type Config = (); - type ResourceDesc = GitDesc; + type Description = GitDescription; type Resource = Utf8PathBuf; type ResolutionError = GitResolutionError; - fn from_config(_: &Self::Config) -> Self { - todo!() - } - - fn resolve(&self, desc: &GitDesc) -> Result { + fn resolve(&self, desc: &GitDescription) -> Result { let clone_path = if let Some(ref local_path) = desc.local_path { Utf8PathBuf::from(local_path) } else { diff --git a/crates/resolver/test_files/A/config.toml b/crates/resolver/test_files/A/config.toml new file mode 100644 index 0000000000..c541cb89be --- /dev/null +++ b/crates/resolver/test_files/A/config.toml @@ -0,0 +1,6 @@ +name = "A" +version = "0.1.0" + +[dependencies] +B = { path = "../B" } +C = { path = "../C" } diff --git a/crates/resolver/test_files/B/config.toml b/crates/resolver/test_files/B/config.toml new file mode 100644 index 0000000000..ee9ae5f3e4 --- /dev/null +++ b/crates/resolver/test_files/B/config.toml @@ -0,0 +1,5 @@ +name = "B" +version = "0.1.0" + +[dependencies] +C = { path = "../C" } diff --git a/crates/resolver/test_files/C/config.toml b/crates/resolver/test_files/C/config.toml new file mode 100644 index 0000000000..20da11a3ff --- /dev/null +++ b/crates/resolver/test_files/C/config.toml @@ -0,0 +1,5 @@ +name = "C" +version = "0.1.0" + +[dependencies] +D = { path = "../D" } diff --git a/crates/resolver/test_files/D/config.toml b/crates/resolver/test_files/D/config.toml new file mode 100644 index 0000000000..6c04043908 --- /dev/null +++ b/crates/resolver/test_files/D/config.toml @@ -0,0 +1,2 @@ +name = "D" +version = "0.1.0" From 87961f56c61816c60b2442b40ccd8f47988dbee2 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Tue, 24 Dec 2024 10:06:21 -0700 Subject: [PATCH 7/7] hacking --- crates/driver2/src/lib.rs | 47 ++++-- crates/driver2/src/main.rs | 7 - crates/resolver/src/ingot/dependencies.rs | 191 ++++++++++++---------- crates/resolver/src/path.rs | 19 --- crates/resolver/src/remote.rs | 27 +-- 5 files changed, 155 insertions(+), 136 deletions(-) diff --git a/crates/driver2/src/lib.rs b/crates/driver2/src/lib.rs index 91a6f90401..438bc8c9b4 100644 --- a/crates/driver2/src/lib.rs +++ b/crates/driver2/src/lib.rs @@ -99,13 +99,14 @@ impl DriverDataBase { } pub fn ingot(&mut self, ingot_path: &path::Path) -> InputIngot { + let ingot_path = Utf8PathBuf::from(ingot_path.to_string_lossy().to_string()); let config_resolver = ConfigResolver; let dep_resolver = DependenciesResolver { config_resolver }; let src_files_resolver = SrcFilesResolver; - let dep_graph = dep_resolver.resolve(ingot_path).unwrap(); + let dep_graph = dep_resolver.resolve(&ingot_path).unwrap(); - let input_ingots = IndexMap::new(); + let mut input_ingots: IndexMap = IndexMap::new(); for path in dep_graph.reverse_toposort() { let ingot_kind = if path == ingot_path { @@ -113,30 +114,42 @@ impl DriverDataBase { } else { IngotKind::External }; - let external_ingots = - dep_graph - .dependencies(&dep) - .iter() - .map(|(name, _, path)| IngotDependency { - name, - ingot: input_ingots[path], - }); - input_ingot[ingot_path] = - InputIngot::new(self, path, ingot_kind, version, external_ingots); + let external_ingots = dep_graph + .dependencies(&path) + .iter() + .map(|(name, (_, path))| IngotDependency { + name: name.to_owned(), + ingot: input_ingots[path].to_owned(), + }) + .collect(); + input_ingots[&ingot_path] = InputIngot::new( + self, + &path.to_string(), + ingot_kind, + Version::new(0, 0, 0), + external_ingots, + ); } - for (ingot_path, input_ingot) in input_ingots { - let files = src_files_resolver.resolve(&ingot_path); + for (ingot_path, input_ingot) in input_ingots.iter() { + let files = src_files_resolver.resolve(&ingot_path).unwrap(); let input_files = files .into_iter() - .map(|(path, content)| InputFile::new(self, input_ingot, file_path, content)) + .map(|(path, content)| { + InputFile::new( + self, + input_ingot.clone(), + path, + String::from_utf8(content).unwrap(), + ) + }) .collect(); - input_ingot.set_files(db, input_files); + input_ingot.set_files(self, input_files); // match lib.fe and main.fe // input_ingot.set_root_file(db, input_files[0]); } - input_ingots[ingot_path] + input_ingots.shift_remove(&ingot_path).unwrap() } pub fn standalone(&mut self, file_path: &path::Path, source: &str) -> InputFile { diff --git a/crates/driver2/src/main.rs b/crates/driver2/src/main.rs index b66991908d..18b10fb368 100644 --- a/crates/driver2/src/main.rs +++ b/crates/driver2/src/main.rs @@ -1,14 +1,7 @@ use clap::{Args, Parser, Subcommand}; -use common::input::{IngotDependency, InputFile}; -use common::{input::IngotKind, InputDb, InputIngot}; -use fe_driver2::DriverDataBase; -use hir::hir_def::TopLevelMod; -use semver::Version; use serde::Deserialize; use std::{collections::BTreeSet, path::Path}; -use walkdir::WalkDir; mod check; -use common::indexmap::IndexSet; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] diff --git a/crates/resolver/src/ingot/dependencies.rs b/crates/resolver/src/ingot/dependencies.rs index a952980f5b..33e40ecb03 100644 --- a/crates/resolver/src/ingot/dependencies.rs +++ b/crates/resolver/src/ingot/dependencies.rs @@ -4,9 +4,8 @@ use crate::path::PathDescription; use crate::remote::GitDescription; use crate::Resolver; use camino::Utf8PathBuf; -use indexmap::IndexMap; -use petgraph::csr::NodeIndex; -use petgraph::graph::DiGraph; +use indexmap::{IndexMap, IndexSet}; +use petgraph::graph::{DiGraph, NodeIndex}; use petgraph::visit::EdgeRef; use petgraph::Direction; use smol_str::SmolStr; @@ -19,36 +18,47 @@ pub enum DependenciesResolutionError { RootConfigResolutionError(ConfigResolutionError), } +pub enum DependencyResolutionError { + InvalidPath, + RemoteDoesNotExist, + ConfigResolutionError, +} + pub struct DependencyGraph { root_path: Utf8PathBuf, graph: DiGraph, nodes: IndexMap, + pub errors: IndexSet, } impl DependencyGraph { pub fn new(root_path: Utf8PathBuf) -> Self { - // let mut graph = DiGraph::new(); - // let node_idx: NodeIndex = graph.add_node(root_path.clone()); - // let mut nodes: IndexMap = IndexMap::new(); - // nodes.insert(local_path.clone(), node_idx); - - // Self { - // root_path, - // graph, - // nodes, - // } - todo!() + let mut graph = DiGraph::new(); + let root_node: NodeIndex = graph.add_node(root_path.clone()); + let mut nodes = IndexMap::new(); + nodes.insert(root_path.clone(), root_node); + Self { + root_path, + graph, + nodes, + errors: IndexSet::new(), + } } pub fn reverse_toposort(&self) -> Vec { - todo!() + petgraph::algo::toposort(&self.graph, None) + .unwrap() + .into_iter() + .map(|node| self.graph[node].clone()) + .rev() + .collect() } pub fn dependencies( &self, path: &Utf8PathBuf, ) -> IndexMap { - let node = NodeIndex::from(self.nodes[path]); + let node = self.nodes[path]; self.graph .edges_directed(node, Direction::Outgoing) .map(|edge| { @@ -72,15 +82,24 @@ impl DependencyGraph { &mut self, name: SmolStr, description: AnyIngotDescription, - from: Utf8PathBuf, - to: Utf8PathBuf, + source_path: &Utf8PathBuf, + target_path: &Utf8PathBuf, ) { - // self.graph.add_edge( - // *self.nodes.get(&from).unwrap(), - // *self.nodes.get(&to).unwrap(), - // (name, description), - // ); - todo!() + let source_node = self.node_index(&source_path); + let target_node = self.node_index(&target_path); + + self.graph + .add_edge(source_node, target_node, (name, description)); + } + + fn node_index(&mut self, path: &Utf8PathBuf) -> NodeIndex { + if !self.contains(path) { + let node = self.graph.add_node(path.to_owned()); + self.nodes.insert(path.to_owned(), node); + node + } else { + self.nodes[path] + } } } @@ -88,12 +107,6 @@ pub struct DependenciesResolver { pub config_resolver: ConfigResolver, } -#[derive(Clone)] -enum DependencyPath { - Local(Utf8PathBuf, Vec), - Remote(GitDescription, Vec), -} - impl DependencyPath { pub fn new_remote(remote_description: GitDescription) -> Self { Self::Remote(remote_description, vec![]) @@ -111,25 +124,24 @@ impl DependencyPath { .push(path_description); } - pub fn fs_path(&self) -> Result { - // match self { - // DependencyPath::Local(_, paths) => paths - // .iter() - // .fold(Utf8PathBuf::new(), |acc, path| acc.join(path)), - // DependencyPath::Remote(git_desc, paths) => paths - // .iter() - // .fold(Utf8PathBuf::new(), |acc, path| acc.join(path)), - // } - todo!() + pub fn path(&self) -> Result { + Ok(match self { + DependencyPath::Local(root_path, path_descriptions) => { + path_descriptions + .iter() + .fold(root_path.to_owned(), |acc, path_description| { + acc.join(Utf8PathBuf::try_from(path_description.path.to_owned()).unwrap()) + }) + } + DependencyPath::Remote(git_description, path_descriptions) => path_descriptions + .iter() + .fold(git_description.relative_path(), |acc, path_description| { + acc.join(Utf8PathBuf::try_from(path_description.path.to_owned()).unwrap()) + }), + }) } } -struct UnresolvedDependency { - name: SmolStr, - ingot_description: AnyIngotDescription, - source: (Utf8PathBuf, DependencyPath), -} - impl Resolver for DependenciesResolver { type Description = Utf8PathBuf; type Resource = DependencyGraph; @@ -147,14 +159,16 @@ impl Resolver for DependenciesResolver { let mut unresolved_dependencies = root_config .dependencies .into_iter() - .map(|(name, ingot_description)| UnresolvedDependency { - name, - ingot_description, - source: ( - description.clone(), - DependencyPath::new_local(description.clone()), - ), - }) + .map( + |(name, ingot_description)| UnresolvedDependencyDescription { + name, + ingot_description, + source: ( + description.clone(), + DependencyPath::new_local(description.clone()), + ), + }, + ) .collect::>(); while let Some(dependency) = unresolved_dependencies.pop() { @@ -172,39 +186,52 @@ impl Resolver for DependenciesResolver { } AnyIngotDescription::Registered(_) => todo!(), }; - let target_path = target.fs_path().unwrap(); - - if !graph.contains(&target_path) { - unresolved_dependencies.append( - &mut self - .config_resolver - .resolve(&target_path) - .unwrap() - .dependencies - .into_iter() - .map(|(name, ingot_description)| UnresolvedDependency { - name, - ingot_description, - source: (target_path.clone(), target.clone()), - }) - .collect::>(), - ) - } - // add a new edge to the dependency graph - graph.add_dependency( - dependency.name, - dependency.ingot_description, - dependency.source.0, - target_path, - ); + match target.path() { + Ok(target_path) => { + if !graph.contains(&target_path) { + unresolved_dependencies.append( + &mut self + .config_resolver + .resolve(&target_path) + .unwrap() + .dependencies + .into_iter() + .map(|(name, ingot_description)| UnresolvedDependency { + name, + ingot_description, + source: (target_path.clone(), target.clone()), + }) + .collect::>(), + ) + } + + graph.add_dependency( + dependency.name, + dependency.ingot_description, + &dependency.source.0, + &target_path, + ); + } + Err(path_error) => todo!(), + } } - // finally, return the graph with all nodes and edges Ok(graph) } } -struct DependencyPathResolver { - root_path: Utf8PathBuf, +#[derive(Clone)] +enum NestedPathsDescription { + Local(Utf8PathBuf, Vec), + Remote(GitDescription, Vec), +} + +struct DependencyDescription { + ingot_description: AnyIngotDescription, + source_path_description: NestedPathsDescription, +} + +struct DependencyResolver { + config_resolver: ConfigResolver, } diff --git a/crates/resolver/src/path.rs b/crates/resolver/src/path.rs index d1902a0051..55c1fdfd46 100644 --- a/crates/resolver/src/path.rs +++ b/crates/resolver/src/path.rs @@ -1,25 +1,6 @@ -use camino::Utf8PathBuf; use serde::Deserialize; -use super::Resolver; - #[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq)] pub struct PathDescription { pub path: String, } - -pub struct PathResolver; - -pub enum PathResolutionError { - AbsolutePathDoesNotExist, -} - -impl Resolver for PathResolver { - type Description = Vec; - type Resource = Utf8PathBuf; - type ResolutionError = PathResolutionError; - - fn resolve(&self, desc: &Vec) -> Result { - todo!() - } -} diff --git a/crates/resolver/src/remote.rs b/crates/resolver/src/remote.rs index 69c3032e3d..a7da3a7dd2 100644 --- a/crates/resolver/src/remote.rs +++ b/crates/resolver/src/remote.rs @@ -9,7 +9,17 @@ use crate::Resolver; pub struct GitDescription { remote: String, refspec: String, - local_path: Option, + path: Option, +} + +impl GitDescription { + pub fn relative_path(&self) -> Utf8PathBuf { + if let Some(ref path) = self.path { + Utf8PathBuf::from(path) + } else { + Utf8PathBuf::from(format!("{}_{}", &self.remote, &self.refspec)) + } + } } pub struct GitResolver { @@ -58,23 +68,18 @@ impl Resolver for GitResolver { type Resource = Utf8PathBuf; type ResolutionError = GitResolutionError; - fn resolve(&self, desc: &GitDescription) -> Result { - let clone_path = if let Some(ref local_path) = desc.local_path { - Utf8PathBuf::from(local_path) - } else { - self.default_clone_path - .join(format!("{}_{}", &desc.remote, &desc.refspec)) - }; + fn resolve(&self, description: &GitDescription) -> Result { + let clone_path = self.default_clone_path.join(description.relative_path()); if clone_path.exists() { let repo = Repository::open(&clone_path).map_err(GitResolutionError::from)?; - if !repo.find_reference(&desc.refspec).is_ok() { + if !repo.find_reference(&description.refspec).is_ok() { fs::remove_dir_all(&clone_path)?; - self.clone_repo(&desc.remote, &clone_path, &desc.refspec)?; + self.clone_repo(&description.remote, &clone_path, &description.refspec)?; } } else { - self.clone_repo(&desc.remote, &clone_path, &desc.refspec)?; + self.clone_repo(&description.remote, &clone_path, &description.refspec)?; } Ok(clone_path)