diff --git a/crates/common2/Cargo.toml b/crates/common2/Cargo.toml index a81984c0b..9331a70ad 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/home_dir.rs b/crates/common2/src/home_dir.rs new file mode 100644 index 000000000..ecd03c568 --- /dev/null +++ b/crates/common2/src/home_dir.rs @@ -0,0 +1,19 @@ +use std::env::VarError; + +use camino::Utf8PathBuf; + +pub struct HomeDir(Utf8PathBuf); + +impl HomeDir { + pub fn load() -> Self { + match std::env::var("HOME") { + Ok(home) => HomeDir(Utf8PathBuf::from(home)), + Err(VarError::NotPresent) => HomeDir(Utf8PathBuf::from("~/.fe")), + Err(_) => panic!("no unicode"), + } + } + + pub fn path(&self) -> Utf8PathBuf { + self.0.clone() + } +} diff --git a/crates/common2/src/input.rs b/crates/common2/src/input.rs index 8da11ca76..b1f40c06e 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, @@ -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); } @@ -103,8 +103,8 @@ pub enum IngotKind { /// An external ingot which is depended on by the current ingot. External, - /// 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 f6cb0fab6..76aa79c97 100644 --- a/crates/common2/src/lib.rs +++ b/crates/common2/src/lib.rs @@ -1,4 +1,5 @@ pub mod diagnostics; +pub mod home_dir; pub mod indexmap; pub mod input; diff --git a/crates/driver2/Cargo.toml b/crates/driver2/Cargo.toml index 0af1b159f..5e8e4abeb 100644 --- a/crates/driver2/Cargo.toml +++ b/crates/driver2/Cargo.toml @@ -16,5 +16,11 @@ 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" +walkdir = "2" +include_dir = "0.7" +dirs = "5.0.1" +serde = { version = "1", features = ["derive"] } diff --git a/crates/driver2/src/check.rs b/crates/driver2/src/check.rs new file mode 100644 index 000000000..6fdbcb308 --- /dev/null +++ b/crates/driver2/src/check.rs @@ -0,0 +1,108 @@ +use crate::CheckArgs; +use common::indexmap::IndexSet; +use common::input::IngotDependency; +use common::{input::IngotKind, InputIngot}; +use fe_driver2::DriverDataBase; +use include_dir::Dir; +use semver::Version; +use std::fs; +use std::{collections::BTreeSet, path::Path}; + +pub fn check_standalone( + 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)); + // } +} + +// 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 e00852638..774827cea 100644 --- a/crates/driver2/src/lib.rs +++ b/crates/driver2/src/lib.rs @@ -2,19 +2,23 @@ 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::{ - 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}, @@ -24,6 +28,7 @@ use hir_analysis::{ }, HirAnalysisDb, }; +use resolver::ingot::{dependency_graph::DependencyGraph, src_files::SourceFiles}; use crate::diagnostics::ToCsDiag; @@ -71,6 +76,63 @@ 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 local_ingot( + &mut self, + core_ingot: InputIngot, + dependency_graph: &DependencyGraph, + ) -> (InputIngot, IndexMap) { + let mut all_ingots = IndexMap::new(); + + for path in dependency_graph.reverse_toposort() { + let external_ingots = dependency_graph + .dependencies(&path) + .into_iter() + .map(|dependency| IngotDependency { + name: dependency.name, + ingot: all_ingots[&dependency.target_path], + }) + .collect(); + + all_ingots[&path] = InputIngot::new( + self, + &path.to_string(), + IngotKind::External, + Version::new(0, 0, 0), + external_ingots, + ); + } + + let local_ingot = all_ingots + .shift_remove(&dependency_graph.local_path) + .expect("local is missing from input ingots"); + (local_ingot, all_ingots) + } + + pub fn core_ingot(&mut self, path: &Utf8PathBuf) -> InputIngot { + todo!(); + } + + pub fn set_ingot_files(&mut self, ingot: InputIngot, files: SourceFiles) { + todo!() + } + 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 1ccababa4..473d4b36b 100644 --- a/crates/driver2/src/main.rs +++ b/crates/driver2/src/main.rs @@ -1,13 +1,31 @@ -use clap::Parser; +use camino::Utf8PathBuf; +use clap::{Args, Parser, Subcommand}; +use common::home_dir::HomeDir; use fe_driver2::DriverDataBase; -use hir::hir_def::TopLevelMod; +use resolver::{ + ingot::{dependency_graph::DependencyGraphResolver, src_files::SourceFilesResolver}, + user_config::{CoreIngotDescription, UserConfigResolver}, + Resolver, +}; +mod check; #[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, /// Dump a graphviz dot file of the scope graph for the given file. #[arg(long = "dump-scope-graph", default_value_t = false)] @@ -15,27 +33,70 @@ struct Args { } 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 source = std::fs::read_to_string(&args.file_path).unwrap(); + let cli = Cli::parse(); + + let Commands::Check(args) = &cli.command; + + let home_dir = HomeDir::load(); + let mut user_config_resolver = UserConfigResolver; + let user_config = user_config_resolver.resolve(&home_dir).unwrap(); + + let core_path: Utf8PathBuf = match user_config.core { + CoreIngotDescription::Local(path_description) => todo!(), + CoreIngotDescription::Remote(git_description) => todo!(), + }; + + let local_path = Utf8PathBuf::from(args.path); + let dependency_graph_resolver = DependencyGraphResolver::new(); + let dependency_graph = dependency_graph_resolver.resolve(&local_path).unwrap(); 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)); - } + + let core_ingot = db.core_ingot(&core_path); + let (local_ingot, external_ingots) = db.local_ingot(core_ingot, &dependency_graph); + // + // let source_files_resolver = SourceFilesResolver::new(); + // for (path, ingot) in external_ingots + // .iter() + // .chain([(&local_path, local_ingot), (&core_path, core_ingot)]) + // { + // let files = source_files_resolver.resolve(path).unwrap(); + // db.set_ingot_files(*ingot, files); + // } } -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() +// 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), +// } + +// 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 run_check(args: &CheckArgs) { + // 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); + // } } diff --git a/crates/hir-analysis/src/ty/ty_def.rs b/crates/hir-analysis/src/ty/ty_def.rs index 81dc80fa0..fa07da488 100644 --- a/crates/hir-analysis/src/ty/ty_def.rs +++ b/crates/hir-analysis/src/ty/ty_def.rs @@ -138,7 +138,7 @@ impl<'db> TyId<'db> { let ty_ingot = self.ingot(db); match ingot.kind(db.as_hir_db()) { - IngotKind::Std => ty_ingot.is_none() || ty_ingot == Some(ingot), + IngotKind::Core => ty_ingot.is_none() || ty_ingot == Some(ingot), _ => ty_ingot == Some(ingot), } } diff --git a/crates/hir/src/analysis_pass.rs b/crates/hir/src/analysis_pass.rs index f162bf3c7..c37625aa8 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/crates/hir/src/hir_def/mod.rs b/crates/hir/src/hir_def/mod.rs index 775fe2e44..9cb1c01b6 100644 --- a/crates/hir/src/hir_def/mod.rs +++ b/crates/hir/src/hir_def/mod.rs @@ -73,8 +73,8 @@ impl<'db> IngotId<'db> { all_impls_in_ingot(db, self) } - pub fn is_std(self, db: &'db dyn HirDb) -> bool { - matches!(self.kind(db), IngotKind::Std) + pub fn is_core(self, db: &'db dyn HirDb) -> bool { + matches!(self.kind(db), IngotKind::Core) } } diff --git a/crates/resolver/Cargo.toml b/crates/resolver/Cargo.toml new file mode 100644 index 000000000..07b71122b --- /dev/null +++ b/crates/resolver/Cargo.toml @@ -0,0 +1,19 @@ +[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" +petgraph = "0.5.1" +common = { path = "../common2", package = "fe-common2" } diff --git a/crates/resolver/src/ingot.rs b/crates/resolver/src/ingot.rs new file mode 100644 index 000000000..464761e3e --- /dev/null +++ b/crates/resolver/src/ingot.rs @@ -0,0 +1,4 @@ +pub mod config; +pub mod dependency; +pub mod dependency_graph; +pub mod src_files; diff --git a/crates/resolver/src/ingot/config.rs b/crates/resolver/src/ingot/config.rs new file mode 100644 index 000000000..e689c3ed8 --- /dev/null +++ b/crates/resolver/src/ingot/config.rs @@ -0,0 +1,133 @@ +use camino::Utf8PathBuf; +use common::indexmap::IndexMap; +use semver::Version; +use serde::Deserialize; +use smol_str::SmolStr; +use std::{collections::HashMap, fs, mem::take}; +use toml; + +use crate::{ + path::{FullPathDescription, PathDescription}, + remote::GitDescription, + Resolver, +}; + +use super::dependency::DependencyDescription; + +#[derive(Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct Config { + pub name: SmolStr, + version: SmolStr, + dependencies: HashMap, +} + +impl Config { + pub fn version(&self) -> Result { + todo!() + } + + pub fn dependency_descriptions( + &self, + source_path: &Utf8PathBuf, + source_path_description: &FullPathDescription, + ) -> Vec { + self.dependencies + .iter() + .map(|(name, ingot_description)| { + let (ingot_description, target_path_description) = match ingot_description { + IngotAndAnyFilesDescription::Path(description) => ( + description.ingot_description.clone(), + source_path_description.push_sub_path(&description.files_description), + ), + // git repo should be resolved below + IngotAndAnyFilesDescription::Remote(description) => ( + description.ingot_description.clone(), + FullPathDescription::new_remote(&description.files_description), + ), + IngotAndAnyFilesDescription::Registered(description) => todo!(), + }; + + DependencyDescription { + name: name.clone(), + source_path: source_path.clone(), + target_path_description, + ingot_description, + } + }) + .collect() + } +} + +#[derive(Debug)] +pub enum ConfigResolutionError { + ConfigNotFound, + FileReadError(std::io::Error), + TomlParseError(toml::de::Error), +} + +#[derive(Debug, Clone)] +pub enum ConfigResolutionDiagnostic { + InvalidVersionFormat, + InvalidNameFormat, +} + +pub struct ConfigResolver { + diagnostics: Vec, + cache: IndexMap, +} + +impl ConfigResolver { + pub fn new() -> Self { + Self { + diagnostics: vec![], + cache: IndexMap::new(), + } + } +} + +impl Resolver for ConfigResolver { + type Description = Utf8PathBuf; + type Resource = Config; + type Error = ConfigResolutionError; + type Diagnostic = ConfigResolutionDiagnostic; + + fn resolve(&mut self, description: &Utf8PathBuf) -> Result { + let config_path = description.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)?; + + Ok(config) + } + + fn take_diagnostics(&mut self) -> Vec { + take(&mut self.diagnostics) + } +} + +#[derive(Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct IngotDescription { + version: Option, + // other fields like "features" would go here +} + +#[derive(Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct IngotAndFilesDescription +where + FD: Clone, +{ + #[serde(flatten)] + pub ingot_description: IngotDescription, + #[serde(flatten)] + pub files_description: FD, +} + +#[derive(Deserialize, Debug, Clone, PartialEq, Eq)] +pub enum IngotAndAnyFilesDescription { + Path(IngotAndFilesDescription), + Remote(IngotAndFilesDescription), + Registered(IngotAndFilesDescription<()>), +} diff --git a/crates/resolver/src/ingot/dependency.rs b/crates/resolver/src/ingot/dependency.rs new file mode 100644 index 000000000..fd898efa1 --- /dev/null +++ b/crates/resolver/src/ingot/dependency.rs @@ -0,0 +1,113 @@ +use std::fmt::Debug; + +use crate::Resolver; +use crate::{path::FullPathDescription, remote::GitResolutionError}; +use camino::Utf8PathBuf; +use semver::Version; +use smol_str::SmolStr; + +use std::mem::take; + +use super::config::{ + ConfigResolutionDiagnostic, ConfigResolutionError, ConfigResolver, IngotDescription, +}; + +#[derive(Clone, Debug)] +pub struct DependencyDescription { + pub name: SmolStr, + pub source_path: Utf8PathBuf, + pub target_path_description: FullPathDescription, + pub ingot_description: IngotDescription, +} + +#[derive(Debug)] +pub enum DependencyResolutionError { + GitResolutionError(GitResolutionError), + TargetPathDoesNotExist, + TargetConfigResolutionError(ConfigResolutionError), +} + +#[derive(Debug, Clone)] +pub enum DependencyResolutionDiagnostic { + IncompatibleVersion, + TargetConfigResolutionError(ConfigResolutionDiagnostic), +} + +#[derive(Debug, Clone)] +pub struct Dependency { + pub name: SmolStr, + pub version: Version, + pub source_path: Utf8PathBuf, + pub target_path: Utf8PathBuf, + pub sub_dependencies: Vec, +} + +pub struct DependencyResolver { + config_resolver: ConfigResolver, + diagnostics: Vec, +} + +impl DependencyResolver { + pub fn new() -> Self { + Self { + config_resolver: ConfigResolver::new(), + diagnostics: vec![], + } + } +} + +impl Resolver for DependencyResolver { + type Description = DependencyDescription; + type Resource = Dependency; + type Error = DependencyResolutionError; + type Diagnostic = DependencyResolutionDiagnostic; + + fn resolve( + &mut self, + description: &DependencyDescription, + ) -> Result { + let target_path = description.target_path_description.path(); + + if !target_path.exists() { + Err(DependencyResolutionError::TargetPathDoesNotExist) + } else { + match self.config_resolver.resolve(&target_path) { + Ok(target_config) => { + let version = target_config.version().unwrap(); + let sub_dependencies = target_config.dependency_descriptions( + &description.source_path, + &description.target_path_description, + ); + + // compare description and target config + + let dependency = Dependency { + name: description.name.clone(), + version, + source_path: description.source_path.clone(), + target_path, + sub_dependencies, + }; + + Ok(dependency) + } + Err(error) => Err(DependencyResolutionError::TargetConfigResolutionError( + error, + )), + } + } + } + + fn take_diagnostics(&mut self) -> Vec { + self.diagnostics.append( + &mut self + .config_resolver + .take_diagnostics() + .into_iter() + .map(DependencyResolutionDiagnostic::TargetConfigResolutionError) + .collect(), + ); + + take(&mut self.diagnostics) + } +} diff --git a/crates/resolver/src/ingot/dependency_graph.rs b/crates/resolver/src/ingot/dependency_graph.rs new file mode 100644 index 000000000..04bc3fec0 --- /dev/null +++ b/crates/resolver/src/ingot/dependency_graph.rs @@ -0,0 +1,194 @@ +use std::{mem::take, str::FromStr}; + +use camino::Utf8PathBuf; +use common::home_dir::HomeDir; +use indexmap::IndexMap; +use petgraph::{ + graph::{DiGraph, NodeIndex}, + Direction, +}; + +use crate::{ + path::FullPathDescription, + user_config::{CoreIngotResolutionError, UserConfigResolver}, + Resolver, +}; + +use super::{ + config::{ConfigResolutionDiagnostic, ConfigResolutionError, ConfigResolver}, + dependency::{ + Dependency, DependencyDescription, DependencyResolutionError, DependencyResolver, + }, +}; + +pub struct DependencyGraph { + pub local_path: Utf8PathBuf, + graph: DiGraph, + nodes: IndexMap, + local_dependencies: Vec, +} + +impl DependencyGraph { + pub fn new(local_path: &Utf8PathBuf) -> Self { + let mut graph = DiGraph::new(); + let local_node: NodeIndex = graph.add_node(local_path.clone()); + let mut nodes = IndexMap::new(); + nodes.insert(local_path.clone(), local_node); + + Self { + local_path: local_path.clone(), + graph, + nodes, + local_dependencies: vec![], + } + } + + pub fn reverse_toposort(&self) -> Vec { + petgraph::algo::toposort(&self.graph, None) + .unwrap() + .into_iter() + .map(|node| self.graph[node].clone()) + .rev() + .collect() + } + + pub fn dependencies(&self, path: &Utf8PathBuf) -> Vec { + let node = self.nodes[path]; + self.graph + .edges_directed(node, Direction::Outgoing) + .map(|edge| edge.weight().clone()) + .collect() + } + + pub fn contains(&self, path: &Utf8PathBuf) -> bool { + self.nodes.contains_key(path) + } + + pub fn add_dependency(&mut self, depedency: Dependency) { + let source_node = self.node_index(&depedency.source_path); + let target_node = self.node_index(&depedency.target_path); + + self.graph.add_edge(source_node, target_node, depedency); + } + + 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] + } + } +} + +pub struct DependencyGraphResolver { + user_config_resolver: UserConfigResolver, + config_resolver: ConfigResolver, + dependency_resolver: DependencyResolver, + diagnostics: Vec, +} + +impl DependencyGraphResolver { + pub fn new() -> Self { + Self { + user_config_resolver: UserConfigResolver::new(), + config_resolver: ConfigResolver::new(), + dependency_resolver: DependencyResolver::new(), + diagnostics: vec![], + } + } +} + +#[derive(Debug)] +pub enum DependencyGraphResolutionError { + LocalPathDoesNotExist, + LocalConfigResolutionError(ConfigResolutionError), +} + +pub enum DependencyGraphResolutionDiagnostic { + CoreIngotResolutionError(CoreIngotResolutionError), + DependencyResolutonError(DependencyDescription, DependencyResolutionError), + ConfigResolutionDiagnostic(ConfigResolutionDiagnostic), +} + +impl Resolver for DependencyGraphResolver { + type Description = Utf8PathBuf; + type Resource = DependencyGraph; + type Error = DependencyGraphResolutionError; + type Diagnostic = DependencyGraphResolutionDiagnostic; + + fn resolve( + &mut self, + description: &Utf8PathBuf, + ) -> Result { + let local_path = description; + + if !local_path.exists() { + Err(DependencyGraphResolutionError::LocalPathDoesNotExist) + } else { + let mut graph = DependencyGraph::new(local_path); + + let local_config = self + .config_resolver + .resolve(local_path) + .map_err(DependencyGraphResolutionError::LocalConfigResolutionError)?; + let local_path_description = FullPathDescription::new_local(local_path); + graph.local_dependencies = + local_config.dependency_descriptions(description, &local_path_description); + + let mut unresolved_dependencies = graph.local_dependencies.clone(); + + while let Some(dependency_description) = unresolved_dependencies.pop() { + match self.dependency_resolver.resolve(&dependency_description) { + Ok(dependency) => { + if !graph.contains(&dependency.target_path) { + unresolved_dependencies.append(&mut dependency.sub_dependencies.clone()) + } + + graph.add_dependency(dependency); + } + Err(error) => self.diagnostics.push( + DependencyGraphResolutionDiagnostic::DependencyResolutonError( + dependency_description, + error, + ), + ), + } + } + + Ok(graph) + } + } + + fn take_diagnostics(&mut self) -> Vec { + // self.diagnostics.append( + // &mut self + // .config_resolver + // .take_diagnostics() + // .into_iter() + // .map(|diag| DependencyGraphResolutionDiagnostic::ConfigResolutionDiagnostic(diag)) + // .collect(), + // ); + + // self.diagnostics.append( + // &mut self + // .user_config_resolver + // .take_diagnostics() + // .into_iter() + // .map(|diag| DependencyGraphResolutionDiagnostic::ConfigResolutionDiagnostic(diag)) + // .collect(), + // ); + + // self.diagnostics.append( + // &mut self + // .dependency_resolver + // .take_diagnostics() + // .into_iter() + // .map(|diag| DependencyGraphResolutionDiagnostic::ConfigResolutionDiagnostic(diag)) + // .collect(), + // ); + + take(&mut self.diagnostics) + } +} diff --git a/crates/resolver/src/ingot/src_files.rs b/crates/resolver/src/ingot/src_files.rs new file mode 100644 index 000000000..216553207 --- /dev/null +++ b/crates/resolver/src/ingot/src_files.rs @@ -0,0 +1,81 @@ +use crate::Resolver; +use camino::Utf8PathBuf; +use common::indexmap::IndexMap; +use std::fs; +use std::io; + +pub struct SourceFiles { + pub files: IndexMap>, +} + +#[derive(Debug)] +pub enum SourceFilesResolutionError { + SourceFolderMissing, + FileReadError(io::Error), +} + +#[derive(Debug)] +pub enum SourceFilesResolutionDiagnostic { + MainFileMissing, + LibFileMissing, +} + +pub struct SourceFilesResolver; + +impl SourceFilesResolver { + pub fn new() -> Self { + Self + } +} + +impl Resolver for SourceFilesResolver { + type Description = Utf8PathBuf; + type Resource = SourceFiles; + type Error = SourceFilesResolutionError; + type Diagnostic = SourceFilesResolutionDiagnostic; + + fn resolve( + &mut self, + description: &Utf8PathBuf, + ) -> Result { + let src_dir = description.join("src"); + + if !src_dir.exists() || !src_dir.is_dir() { + return Err(SourceFilesResolutionError::SourceFolderMissing); + } + + let mut files = IndexMap::new(); + + collect_files_and_contents(&src_dir, &mut files)?; + + Ok(SourceFiles { files }) + } + + fn take_diagnostics(&mut self) -> Vec { + todo!() + } +} + +fn collect_files_and_contents( + dir: &Utf8PathBuf, + file_map: &mut IndexMap>, +) -> Result<(), SourceFilesResolutionError> { + for entry in fs::read_dir(dir).map_err(SourceFilesResolutionError::FileReadError)? { + let entry = entry.map_err(SourceFilesResolutionError::FileReadError)?; + let path = Utf8PathBuf::from_path_buf(entry.path()).map_err(|_| { + SourceFilesResolutionError::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(SourceFilesResolutionError::FileReadError)?; + file_map.insert(path, content); + } + } + + Ok(()) +} diff --git a/crates/resolver/src/lib.rs b/crates/resolver/src/lib.rs new file mode 100644 index 000000000..5ab07e9c4 --- /dev/null +++ b/crates/resolver/src/lib.rs @@ -0,0 +1,14 @@ +pub mod ingot; +pub mod path; +pub mod remote; +pub mod user_config; + +pub trait Resolver { + type Description; + type Resource; + type Error; + type Diagnostic; + + fn resolve(&mut self, description: &Self::Description) -> Result; + fn take_diagnostics(&mut self) -> Vec; +} diff --git a/crates/resolver/src/path.rs b/crates/resolver/src/path.rs new file mode 100644 index 000000000..3b1019a3d --- /dev/null +++ b/crates/resolver/src/path.rs @@ -0,0 +1,64 @@ +use camino::Utf8PathBuf; +use serde::Deserialize; + +use crate::remote::GitDescription; + +#[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq)] +pub struct PathDescription { + pub path: String, +} + +#[derive(Clone, Debug)] +enum PathHead { + Local(Utf8PathBuf), + Remote(GitDescription), +} + +#[derive(Clone, Debug)] +pub struct FullPathDescription { + head: PathHead, + sub_paths: Vec, +} + +impl FullPathDescription { + pub fn new_local(local_path: &Utf8PathBuf) -> Self { + FullPathDescription { + head: PathHead::Local(local_path.clone()), + sub_paths: vec![], + } + } + + pub fn new_remote(git_description: &GitDescription) -> Self { + FullPathDescription { + head: PathHead::Remote(git_description.clone()), + sub_paths: vec![], + } + } + + pub fn path(&self) -> Utf8PathBuf { + match &self.head { + PathHead::Local(local_path) => { + self.sub_paths + .iter() + .fold(local_path.clone(), |acc, path_description| { + acc.join(Utf8PathBuf::from(path_description.path.to_owned())) + }) + } + PathHead::Remote(git_description) => self.sub_paths.iter().fold( + git_description.relative_path(), + |acc, path_description| { + acc.join(Utf8PathBuf::from(path_description.path.to_owned())) + }, + ), + } + } + + pub fn push_sub_path(&self, path_description: &PathDescription) -> Self { + let mut sub_paths = self.sub_paths.clone(); + sub_paths.push(path_description.clone()); + Self { + head: self.head.clone(), + sub_paths, + } + } +} diff --git a/crates/resolver/src/remote.rs b/crates/resolver/src/remote.rs new file mode 100644 index 000000000..fb0e01053 --- /dev/null +++ b/crates/resolver/src/remote.rs @@ -0,0 +1,135 @@ +use camino::Utf8PathBuf; +use git2::{Error as Git2Error, FetchOptions, Oid, Repository}; +use serde::Deserialize; +use std::fs; + +use crate::Resolver; + +#[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq)] +pub struct GitDescription { + remote: String, + refspec: String, + 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 { + default_clone_path: Utf8PathBuf, +} + +impl Default for GitResolver { + fn default() -> Self { + GitResolver { + default_clone_path: Utf8PathBuf::from(""), + } + } +} + +#[derive(Debug)] +pub enum GitResolutionError { + GitError(Git2Error), + IoError(std::io::Error), + InvalidOid, +} + +#[derive(Debug)] +pub enum GitResolutionDiagnostic { + RefspecDoesNotMatch(GitDescription), + UncommittedChanges(GitDescription), +} + +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 Description = GitDescription; + type Resource = Utf8PathBuf; + type Error = GitResolutionError; + type Diagnostic = GitResolutionDiagnostic; + + fn resolve(&mut 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(&description.refspec).is_ok() { + fs::remove_dir_all(&clone_path)?; + self.clone_repo(&description.remote, &clone_path, &description.refspec)?; + } + } else { + self.clone_repo(&description.remote, &clone_path, &description.refspec)?; + } + + Ok(clone_path) + } + + fn take_diagnostics(&mut self) -> Vec { + vec![] + } +} + +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/user_config.rs b/crates/resolver/src/user_config.rs new file mode 100644 index 000000000..24da1692d --- /dev/null +++ b/crates/resolver/src/user_config.rs @@ -0,0 +1,88 @@ +use std::{fs, str::FromStr}; + +use crate::{ + path::PathDescription, + remote::{GitDescription, GitResolutionError}, + Resolver, +}; +use camino::Utf8PathBuf; +use common::home_dir::HomeDir; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct UserConfig { + // could also include things like ingot registries and settings for the language server. + pub core: CoreIngotDescription, +} + +pub struct UserConfigResolver; + +impl UserConfigResolver { + pub fn new() -> Self { + Self + } +} + +#[derive(Debug)] +pub enum UserConfigResolutionError { + HomePathDoesNotExist, + UserConfigDoesNotExist, + FileReadError(std::io::Error), + TomlParseError(toml::de::Error), +} + +#[derive(Debug)] +pub enum UserConfigResolutionDiagnostic { + CoreNotSet, +} + +impl Resolver for UserConfigResolver { + type Description = HomeDir; + type Resource = UserConfig; + type Error = UserConfigResolutionError; + type Diagnostic = UserConfigResolutionDiagnostic; + + fn resolve(&mut self, description: &HomeDir) -> Result { + let home_path = description.path(); + let config_path = home_path.join("config.toml"); + + let file_content = + fs::read_to_string(&config_path).map_err(UserConfigResolutionError::FileReadError)?; + + let config: UserConfig = + toml::from_str(&file_content).map_err(UserConfigResolutionError::TomlParseError)?; + + Ok(config) + } + + fn take_diagnostics(&mut self) -> Vec { + todo!() + } +} + +#[derive(Debug, Deserialize)] +pub enum CoreIngotDescription { + Local(PathDescription), + Remote(GitDescription), +} + +pub enum CoreIngotResolutionError { + CoreIngotPathDoesNotExist, + RemoteResolutionError(GitResolutionError), +} + +/* +pub struct CoreIngotResolver { + // ... +} + +impl Resolver for CoreIngotResolver { + type Description = CoreIngotDescription; + type Resource = Utf8PathBuf; + type Error = CoreIngotResolutionError; + + fn resolve(&self, description: &CoreIngotDescription) -> Result { + // ... + } +} +*/ diff --git a/crates/resolver/test_files/A/config.toml b/crates/resolver/test_files/A/config.toml new file mode 100644 index 000000000..c541cb89b --- /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 000000000..ee9ae5f3e --- /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 000000000..20da11a3f --- /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 000000000..6c0404390 --- /dev/null +++ b/crates/resolver/test_files/D/config.toml @@ -0,0 +1,2 @@ +name = "D" +version = "0.1.0" diff --git a/library/core/config.toml b/library/core/config.toml new file mode 100644 index 000000000..22ac511f8 --- /dev/null +++ b/library/core/config.toml @@ -0,0 +1,4 @@ +[package] +name = "core" +version = "1.0.0" +library = "none" diff --git a/library/core/src/cmp.fe b/library/core/src/cmp.fe new file mode 100644 index 000000000..e69de29bb diff --git a/library/core/src/cmp/cmp.fe b/library/core/src/cmp/cmp.fe new file mode 100644 index 000000000..57bf955f4 --- /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 000000000..e69de29bb diff --git a/library/core/src/ctrl/applicative.fe b/library/core/src/ctrl/applicative.fe new file mode 100644 index 000000000..dd828284c --- /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 000000000..002d31de1 --- /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 000000000..42346e4c4 --- /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 000000000..ded9eb27f --- /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 000000000..bd65b693e --- /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 000000000..4f5e1e8e4 --- /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 000000000..1c5a18844 --- /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 000000000..68227e89c --- /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 000000000..e69de29bb diff --git a/library/core/src/data/list.fe b/library/core/src/data/list.fe new file mode 100644 index 000000000..ff7bc3519 --- /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 000000000..37f24b7b3 --- /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 000000000..b6b588295 --- /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 000000000..9e69fcea0 --- /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 000000000..7479800a8 --- /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 000000000..e69de29bb diff --git a/library/core/src/data/tuple.fe b/library/core/src/data/tuple.fe new file mode 100644 index 000000000..1fed8896f --- /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 000000000..1af044076 --- /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 000000000..e69de29bb diff --git a/library/core/src/num.fe b/library/core/src/num.fe new file mode 100644 index 000000000..1d75fe8fe --- /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 000000000..2b4b5b2fd --- /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 000000000..03656fe05 --- /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/std-evm/config.toml b/library/std-evm/config.toml new file mode 100644 index 000000000..636e99043 --- /dev/null +++ b/library/std-evm/config.toml @@ -0,0 +1,5 @@ +[package] +name = "std-evm" +version = "1.0.0" +library = "std" +platform = "evm" diff --git a/library/std-evm/src/data/list.fe b/library/std-evm/src/data/list.fe new file mode 100644 index 000000000..fe85b0249 --- /dev/null +++ b/library/std-evm/src/data/list.fe @@ -0,0 +1 @@ +// use ingot::target::evm::{alloc} \ No newline at end of file diff --git a/library/std-evm/src/lib.fe b/library/std-evm/src/lib.fe new file mode 100644 index 000000000..e69de29bb diff --git a/library/std-evm/src/target/evm.fe b/library/std-evm/src/target/evm.fe new file mode 100644 index 000000000..8421e445b --- /dev/null +++ b/library/std-evm/src/target/evm.fe @@ -0,0 +1,10 @@ +// struct MemBuf { +// fn read() -> +// fn write() +// } + +// extern { +// alloc(size: usize) -> ??????? +// } + +