diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 40b73ec..c1389b4 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,11 +7,17 @@ - + + + + + + + @@ -743,7 +752,6 @@ - @@ -756,7 +764,8 @@ - diff --git a/main.why b/main.why index 85502e7..bf9dcb6 100644 --- a/main.why +++ b/main.why @@ -1,4 +1,4 @@ -use std/linked_list.why; +use std/; fn main() -> int { diff --git a/src/root/compiler/compile.rs b/src/root/compiler/compile.rs index 0712322..6f143cb 100644 --- a/src/root/compiler/compile.rs +++ b/src/root/compiler/compile.rs @@ -1,7 +1,9 @@ -use std::collections::HashMap; - #[cfg(debug_assertions)] use itertools::Itertools; +use std::collections::HashMap; +use std::io::{stdout, Write}; +use std::thread; +use std::time::{Duration, Instant}; use crate::root::compiler::compile_function::compile_function; use crate::root::compiler::global_tracker::GlobalTracker; @@ -19,10 +21,14 @@ pub fn compile( path_storage: &PathStorage, ) -> Result { let mut unprocessed_functions = unprocessed_functions; + // TODO: Write assembly to disk asynchronously while compiling let mut compiled_functions = new_hashmap(); let mut compiled_len = 0usize; let mut open_set = new_hashset(); + let mut compiled_count: usize = 0; + let mut last_shown = Instant::now(); + open_set.insert(FunctionID(0)); // Start with main let mut global_tracker = GlobalTracker::new(path_storage); @@ -31,6 +37,8 @@ pub fn compile( let current_function = *open_set.iter().next().unwrap(); open_set.remove(¤t_function); + + compiled_count += 1; let Some(current_function_token) = unprocessed_functions.remove(¤t_function) else { continue; // Inline function @@ -51,7 +59,22 @@ pub fn compile( open_set.insert(*called); } } + + if Instant::now() - last_shown > Duration::from_millis(1000) { + print!( + "\n - {}/{} Functions Compiled", + compiled_count, + open_set.len() + compiled_count + ); + last_shown = Instant::now(); + } } + print!( + "\n - {}/{} Functions Compiled", + compiled_count, + open_set.len() + compiled_count + ); + println!(); let mut s = String::with_capacity(compiled_len); diff --git a/src/root/parser/mod.rs b/src/root/parser/mod.rs index 79b242d..d3bb395 100644 --- a/src/root/parser/mod.rs +++ b/src/root/parser/mod.rs @@ -6,6 +6,7 @@ pub mod parse_blocks; pub mod parse_comments; pub mod parse_function; pub mod parse_impl; +mod parse_imports; pub mod parse_name; pub mod parse_name_old; pub mod parse_parameters; @@ -14,4 +15,3 @@ pub mod parse_toplevel; pub mod parse_util; pub mod path_storage; pub mod soft_alt; -mod use_parser; diff --git a/src/root/parser/parse.rs b/src/root/parser/parse.rs index e21791e..9a95fb1 100644 --- a/src/root/parser/parse.rs +++ b/src/root/parser/parse.rs @@ -9,10 +9,10 @@ use crate::root::errors::parser_errors::ParseError; use crate::root::errors::WErr; use crate::root::parser::handle_errors::handle_error; use crate::root::parser::location::Location; +use crate::root::parser::parse_imports::parse_imports; use crate::root::parser::parse_toplevel; use crate::root::parser::parse_toplevel::TopLevelTokens; use crate::root::parser::path_storage::{FileID, PathStorage}; -use crate::root::parser::use_parser::parse_uses; pub type Span<'a> = LocatedSpan<&'a str, FileID>; @@ -35,7 +35,7 @@ pub fn parse(path_storage: &mut PathStorage) -> Result, WErr let base = Span::new_extra(&text, file_id); - let (after_use, new_files) = handle_error(parse_uses(base, path_storage), path_storage)?; + let (after_use, new_files) = handle_error(parse_imports(base, path_storage, file_id), path_storage)?; path_queue.extend(new_files); let res = parse_toplevel::parse_toplevel(after_use); diff --git a/src/root/parser/use_parser.rs b/src/root/parser/parse_imports.rs similarity index 78% rename from src/root/parser/use_parser.rs rename to src/root/parser/parse_imports.rs index 6b6364c..26a3078 100644 --- a/src/root/parser/use_parser.rs +++ b/src/root/parser/parse_imports.rs @@ -7,15 +7,21 @@ use crate::root::parser::parse::{ErrorTree, ParseResult, Span}; use crate::root::parser::parse_util::discard_ignored; use crate::root::parser::path_storage::{FileID, PathStorage}; -pub fn parse_uses<'a>( +pub fn parse_imports<'a>( s: Span<'a>, path_storage: &mut PathStorage, + current_file: FileID, ) -> ParseResult<'a, Span<'a>, Vec<(FileID, Location)>> { let mut s = s; let mut found_paths = Vec::new(); loop { let (ns, _) = discard_ignored(s)?; - let Ok((ns, _)) = tag::<_, _, ErrorTree>("use")(ns) else { + let mut is_use = true; + + let Ok((ns, _)) = tag::<_, _, ErrorTree>("use")(ns).or_else(|_| { + is_use = false; + tag::<_, _, ErrorTree>("import")(ns) + }) else { return Ok((ns, found_paths)); }; @@ -37,9 +43,9 @@ pub fn parse_uses<'a>( )); } - let (_, (id, new)) = path_storage.get_file_path_id_checked(path)?; - - if new { + let (_, ids) = path_storage.get_id_and_add_to_file(current_file, is_use, path)?; + + for id in ids { found_paths.push((id, Location::from_span(&path))); } diff --git a/src/root/parser/path_storage.rs b/src/root/parser/path_storage.rs index dfefaa7..0c69666 100644 --- a/src/root/parser/path_storage.rs +++ b/src/root/parser/path_storage.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; - -use nom::character::complete::anychar; - +use std::fs; use crate::root::errors::parser_errors::create_custom_error; use crate::root::errors::WErr; use crate::root::parser::parse::{ErrorTree, ParseResult, Span}; use crate::root::utils::identify_first_last::IdentifyLast; +use nom::character::complete::anychar; +use nom::InputTake; #[derive(Hash, Copy, Clone, Debug, Eq, PartialEq)] pub struct FileID(usize); @@ -40,7 +40,8 @@ struct CodeFile { parent: FolderID, current: String, use_files: Vec, - use_folders: Vec, + imported_files: Vec, + imported_folders: Vec, // Use folder converts to import subfiles + folders } pub struct PathStorage { @@ -51,6 +52,9 @@ pub struct PathStorage { impl PathStorage { pub fn new(main: &str) -> Result { // TODO: Only allow certain characters in base + if !main.ends_with(".why") { todo!() } + let main = &main[..main.len() - ".why".len()]; + let mut folders = vec![CodeFolder::root()]; let mut files = Vec::new(); @@ -61,7 +65,8 @@ impl PathStorage { parent: current, current: section.to_string(), use_files: vec![], - use_folders: vec![], + imported_files: vec![], + imported_folders: vec![], }); } else { folders.push(CodeFolder { @@ -95,10 +100,10 @@ impl PathStorage { } pub fn reconstruct_file(&self, id: FileID) -> String { - let mut sb = self.get_file(id).current.clone(); + let mut sb = self.get_file(id).current.clone() + ".why"; let mut current = self.get_file(id).parent; while current.0 != 0 { - sb = self.get_folder(current).current.clone() + "/" + &sb; + sb = self.get_folder(current).current.clone() + std::path::MAIN_SEPARATOR_STR + &sb; current = self.get_folder(current).parent; } sb @@ -108,33 +113,62 @@ impl PathStorage { let mut sb = self.get_folder(id).current.to_string(); let mut current = self.get_folder(id).parent; while current.0 != 0 { - sb = self.get_folder(current).current.clone() + "/" + &sb; + sb = self.get_folder(current).current.clone() + std::path::MAIN_SEPARATOR_STR + &sb; current = self.get_folder(current).parent; } sb } - pub fn get_file_path_id_checked<'a>( + pub fn get_id_and_add_to_file<'a>( &mut self, + current_file: FileID, + is_use: bool, path: Span<'a>, - ) -> ParseResult<(), (FileID, bool), ErrorTree<'a>> { + ) -> ParseResult<(), Vec, ErrorTree<'a>> { let mut path_rem = path; - let mut last_dot = false; + + let Some(last) = path_rem.chars().last() else { + todo!() + }; + // let wildcard = if last == '*' { + // let (_, p) = path_rem.take_split(path_rem.len() - 1); + // path_rem = p; + // true + // } else { + // false + // }; + + let is_folder = if let Some(last) = path_rem.chars().last() { + if last == '/' { + let (_, p) = path_rem.take_split(path_rem.len() - 1); + path_rem = p; + true + } else { + false + } + } else { + false + }; + + let is_absolute = if let Some(last) = path_rem.chars().next() { + if last == '/' { + let (p, _) = path_rem.take_split(1); + path_rem = p; + true + } else { + false + } + } else { + false + }; + + // if wildcard && !is_folder { + // todo!() + // } + while let Ok((rem, c)) = anychar::<_, ErrorTree>(path_rem) { if c.is_alphanumeric() || c == '_' || c == '/' { - last_dot = false; - path_rem = rem; - continue; - } - if c == '.' { - if last_dot { - return Err(create_custom_error( - "Double '.'s not allowed in path".to_string(), - path_rem, - )); - } path_rem = rem; - last_dot = true; continue; } @@ -150,44 +184,101 @@ impl PathStorage { )); } - let mut current = FolderID(0); + let mut current: FolderID = if is_absolute { + FolderID(0) + } else { + self.get_file(current_file).parent + }; - for (is_last, section) in path.split('/').identify_last() { + for (is_last, section) in path.split_terminator('/').identify_last() { if is_last { - return if let Some(id) = self.get_folder(current).child_files.get(section) { - Ok(((), (*id, false))) + if is_folder { + let folder = self.add_folder(section, current); + if !is_use { + self.get_file_mut(current_file).imported_folders.push(folder); + } + let folder_path = self.reconstruct_folder(folder); + let mut new_files = Vec::new(); + + let Ok(subpaths) = fs::read_dir(folder_path) else { todo!() }; + for path in subpaths { + let Ok(path) = path else { todo!() }; + let Ok(t) = path.file_type() else { todo!() }; + if !t.is_file() { continue; } + let path = path.path(); + if !path.extension().and_then(|e| e.to_str()).is_some_and(|e| e == "why") { + continue; + } + let Some(name) = path.file_stem().and_then(|f| f.to_str()) else { todo!() }; + + let (file, is_new) = self.add_file(name, folder); + if is_new { new_files.push(file); } + if is_use { + self.get_file_mut(current_file).imported_files.push(file); + } + } + + return Ok(((), new_files)); } else { - self.files.push(CodeFile { - parent: current, - current: section.to_string(), - use_files: vec![], - use_folders: vec![], - }); - let id = FileID(self.files.len() - 1); - self.get_folder_mut(current) - .child_files - .insert(section.to_string(), id); - Ok(((), (id, true))) - }; + let (file, is_new) = self.add_file(section, current); + if file == current_file { + todo!(); + } + + if is_use { + self.get_file_mut(current_file).use_files.push(file); + } else { + self.get_file_mut(current_file).imported_files.push(file); + } + + return if is_new { + Ok(((), vec![file])) + } else { + Ok(((), vec![])) + } + } } else { - current = if let Some(id) = self.get_folder(current).child_folders.get(section) { - *id - } else { - self.folders.push(CodeFolder { - parent: current, - child_folders: Default::default(), - child_files: Default::default(), - current: section.to_string(), - }); - let id = FolderID(self.folders.len() - 1); - self.get_folder_mut(current) - .child_folders - .insert(section.to_string(), id); - id - }; + current = self.add_folder(section, current); } } panic!() } + + fn add_file(&mut self, name: &str, parent: FolderID) -> (FileID, bool) { + if let Some(id) = self.get_folder(parent).child_files.get(name) { + (*id, false) + } else { + self.files.push(CodeFile { + parent, + current: name.to_string(), + use_files: vec![], + imported_files: vec![], + imported_folders: vec![], + }); + let id = FileID(self.files.len() - 1); + self.get_folder_mut(parent) + .child_files + .insert(name.to_string(), id); + (id, true) + } + } + + fn add_folder(&mut self, name: &str, parent: FolderID) -> FolderID { + if let Some(id) = self.get_folder(parent).child_folders.get(name) { + *id + } else { + self.folders.push(CodeFolder { + parent, + child_folders: Default::default(), + child_files: Default::default(), + current: name.to_string(), + }); + let id = FolderID(self.folders.len() - 1); + self.get_folder_mut(parent) + .child_folders + .insert(name.to_string(), id); + id + } + } }