From 502bde1536492741603db492654e04936bcca232 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 28 Jun 2026 17:38:16 +0200 Subject: [PATCH] Updated boostrap --- crates/mist-api/src/builder.mist | 107 ++++++---------- crates/mist-api/src/modules.mist | 45 +++---- crates/mist-api/src/transpiler.mist | 181 +++++++++------------------- src/analyzer.mist | 3 +- src/main.mist | 55 +++------ 5 files changed, 129 insertions(+), 262 deletions(-) diff --git a/crates/mist-api/src/builder.mist b/crates/mist-api/src/builder.mist index 6571786..598886e 100644 --- a/crates/mist-api/src/builder.mist +++ b/crates/mist-api/src/builder.mist @@ -1,16 +1,24 @@ pub module builder; use std::collections::HashMap; + use std::fs; + use std::path::PathBuf; + use std::process::Command; + use std::process::Stdio; + use cargo_metadata::CompilerMessage; + use cargo_metadata::Message; + use mist_parser::rev_mapper; #[derive(Debug, Clone)] -pub struct MistDiagnosticMessage { +pub struct MistDiagnosticMessage +{ pub String message, pub PathBuf file_path, pub String file_name, @@ -19,62 +27,42 @@ pub struct MistDiagnosticMessage { } #[derive(Debug, Clone)] -pub enum MistDiagnostic { +pub enum MistDiagnostic +{ Error(MistDiagnosticMessage), Warning(MistDiagnosticMessage), Rust(CompilerMessage), } -pub bool build(Vec mut args, PathBuf root) { +pub bool build(Vec mut args, PathBuf root) +{ args.remove(0); args.insert(1, "--message-format=json".to_string()); - - let mut command = Command::new("cargo") - .args(args) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .stdin(Stdio::inherit()) - .spawn() - .expect("Failed to run cargo"); - + let mut command = Command::new("cargo").args(args).stdout(Stdio::piped()).stderr(Stdio::inherit()).stdin(Stdio::inherit()).spawn().expect("Failed to run cargo"); let mut reader = std::io::BufReader::new(command.stdout.take().expect("Failed to get reader")); - let mut diagnostics = Vec::new(); - let mut mapping = HashMap::new(); - for message in cargo_metadata::Message::parse_stream(&mut reader) { match message { Ok(Message::CompilerMessage(msg)) => { for span in &msg.message.spans { if span.is_primary { let rust_path = root.join(&span.file_name); - let mapping_path = rust_path.with_extension("map.json"); - if !fs::exists(&mapping_path).expect("Unable to check if map file exists") { diagnostics.push(MistDiagnostic::Rust(msg)); break; } - let map = mapping.entry(mapping_path.clone()).or_insert_with(() => { let map_str = fs::read_to_string(mapping_path).expect("Failed to read map file"); - serde_json::from_str(&map_str).expect("Failed to parse map file") }); - let mist_file = map.mist_path.strip_prefix(&root); - - let (_, rev_mapper::MistMap(line, column)) = - map.find(&rev_mapper::RustMap(span.line_end, span.column_start)) - .expect("Unable to find mapping"); - + let (_, rev_mapper::MistMap(line, column)) = map.find(&rev_mapper::RustMap(span.line_end, span.column_start)).expect("Unable to find mapping"); let mist_msg = MistDiagnosticMessage { - message: format!( - "{}: {}", + message: format!("{}: {}", msg.message.message, - span.label.clone().unwrap_or_default() - ), + span.label.clone().unwrap_or_default()), file_name: if let Ok(mist_file) = mist_file { mist_file.to_string_lossy().to_string() } else { @@ -82,97 +70,70 @@ pub bool build(Vec mut args, PathBuf root) { }, file_path: map.mist_path.clone(), line: line, - column: column + column: column, }; - match msg.message.level { cargo_metadata::diagnostic::DiagnosticLevel::Error => { diagnostics.push(MistDiagnostic::Error(mist_msg)) } - cargo_metadata::diagnostic::DiagnosticLevel::Warning => { diagnostics.push(MistDiagnostic::Warning(mist_msg)) } - - _ => {} + _ => { + } } } } } - Ok(Message::BuildFinished(finish)) => { print_diagnostics(&diagnostics); - let mut raw_reader = reader.into_inner(); let mut stdout = std::io::stdout(); - - std::io::copy(&mut raw_reader, &mut stdout) - .map_err((v) => v.to_string()) - .expect("(Mist) Failed to copy IO"); - + std::io::copy(&mut raw_reader, &mut stdout).map_err((v) => v.to_string()).expect("(Mist) Failed to copy IO"); command.wait().unwrap(); - return finish.success; } - - Ok(Message::TextLine(text)) => println!("{text}"); - _ => {} + Ok(Message::TextLine(text)) => println!("{text}"), + _ => { + } } } - false } -pub void print_diagnostics(Vec& diagnostics) { +pub void print_diagnostics(Vec& diagnostics) +{ let mut files = HashMap::new(); - for diag in diagnostics { match diag { MistDiagnostic::Error(msg) => { let line = get_line(&mut files, &msg); - - println!( - "\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}", + println!("\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}", msg.file_name, msg.line, msg.column, msg.message, - line.unwrap_or_default(), - ) + line.unwrap_or_default(),) } - MistDiagnostic::Warning(msg) => { let line = get_line(&mut files, &msg); - - println!( - "\n{}:{}:{}\n \x1b[33mWarning\x1b[0m: {}\n\t{}", + println!("\n{}:{}:{}\n \x1b[33mWarning\x1b[0m: {}\n\t{}", msg.file_name, msg.line, msg.column, msg.message, - line.unwrap_or_default(), - ) + line.unwrap_or_default(),) } - - MistDiagnostic::Rust(rs) => println!("{rs}"); + MistDiagnostic::Rust(rs) => println!("{rs}"), } } } -pub Option get_line( - HashMap> mut& files, - MistDiagnosticMessage& msg, -) { +pub Option get_line(HashMap> mut& files, MistDiagnosticMessage& msg) +{ let src_path = msg.file_path.clone(); - let lines = files.entry(src_path.clone()).or_insert_with(() => { - fs::read_to_string(src_path) - .expect("Unable to read mist file") - .lines() - .into_iter() - .map(String::from) - .collect() + fs::read_to_string(src_path).expect("Unable to read mist file").lines().into_iter().map(String::from).collect() }); - lines.get(msg.line - 1).map((v) => v.trim().to_string()) } diff --git a/crates/mist-api/src/modules.mist b/crates/mist-api/src/modules.mist index af7b8b3..bd9c29c 100644 --- a/crates/mist-api/src/modules.mist +++ b/crates/mist-api/src/modules.mist @@ -1,75 +1,72 @@ pub module modules; use std::path::Path; + use std::path::PathBuf; + use std::fs; + use std::process; use crate::transpiler::MistConfig; #[derive(Debug)] -pub class Module { +pub class Module +{ pub String name; pub PathBuf path; pub Vec children; - pub constructor(PathBuf mist_path, MistConfig& config) { + pub constructor(PathBuf mist_path, MistConfig& config) + { self.children = Vec::new(); - self.name = mist_path.file_stem() - .and_then((s) => s.to_str()) - .expect("Failed to get module name") - .to_string(); + self.name = mist_path.file_stem().and_then((s) => s.to_str()).expect("Failed to get module name").to_string(); self.path = mist_path; - if self.path.is_dir() { let dir = self.path.clone(); - let pkg_gate = self.path.join("package.mist"); if pkg_gate.exists() { self.path = pkg_gate; } - self.scan_directory(&dir, config); } else if config.should_ignore(&self.path) { let dir = self.path.parent().expect("Failed to get parent directory to scan").to_path_buf(); - self.scan_directory(&dir, config); } } - void scan_directory(&mut self, Path& search_dir, MistConfig& config) { + void scan_directory(&mut self, Path& search_dir, MistConfig& config) + { let entries = match fs::read_dir(search_dir) { - Ok(entries) => entries; + Ok(entries) => entries, Err(e) => { eprintln!("error: failed to read directory {}\n {}", search_dir.display(), e); process::exit(1); } }; - for entry in entries { let entry = match entry { - Ok(entry) => entry; + Ok(entry) => entry, Err(e) => { eprintln!("error: failed to read directory entry\n {}", e); process::exit(1); } }; - let child_path = entry.path(); - if child_path == self.path || child_path == config.package { continue; } - self.children.push(Module::new(child_path, config)); } } - pub bool is_package(&self) { + pub bool is_package(&self) + { self.path.file_name().map((v) => v.to_str()).unwrap_or_default() == Some("package.mist") } - pub PathBuf output_dir(&self, PathBuf& parent_dir) { + pub PathBuf output_dir(&self, PathBuf& parent_dir) + { if self.path.is_dir() || self.is_package() { parent_dir.join(&self.name) } else { @@ -77,19 +74,13 @@ pub class Module { } } - pub PathBuf output_path(&self, - PathBuf& parent_dir, - Option<( - mist_parser::ast::Visibility, - mist_parser::ast::Identifier - )>& curr_mod_decl - ) { + pub PathBuf output_path(&self, PathBuf& parent_dir, Option<(mist_parser::ast::Visibility, mist_parser::ast::Identifier)>& curr_mod_decl) + { let name = if let Some((_, name)) = curr_mod_decl { &name.0 } else { &self.name }; - if self.path.is_dir() || self.is_package() { parent_dir.join(name).join("mod.rs") } else { diff --git a/crates/mist-api/src/transpiler.mist b/crates/mist-api/src/transpiler.mist index 095328f..a6808c8 100644 --- a/crates/mist-api/src/transpiler.mist +++ b/crates/mist-api/src/transpiler.mist @@ -1,43 +1,54 @@ pub module transpiler; use std::fs; + use std::path::Path; + use std::path::PathBuf; + use std::process; + use std::time; + use std::env; use mist_parser::error; + use crate::modules; + use mist_codegen::GetRust; use serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(default)] -pub struct MistConfig { +pub struct MistConfig +{ pub PathBuf package, pub Vec packages, - pub String main_mods + pub String main_mods, } -impl MistConfig { - pub bool should_ignore(&self, Path& path) { +impl MistConfig +{ + pub bool should_ignore(&self, Path& path) + { if path == self.package { return true; } - for pkg in &self.packages { if path.ends_with(pkg) { return true; } } - false } } -impl Default for MistConfig { - Self default() { + +impl Default for MistConfig +{ + Self default() + { Self { package: PathBuf::from("main.mist"), packages: Vec::new(), @@ -46,125 +57,85 @@ impl Default for MistConfig { } } -pub PathBuf transpile() { +pub PathBuf transpile() +{ let start = time::Instant::now(); - let root = env::current_dir().expect("Unable to find project root"); - let toml_path = root.join("Mist.toml"); let src = root.join("src"); let out = root.join(".mist/src"); - - let toml_content = fs::read_to_string(&toml_path) - .unwrap_or_else((_) => panic!("Could not read file at {:?}", toml_path)); - - MistConfig mut config = toml::from_str(&toml_content) - .unwrap_or_else((_) => panic!("Failed to parse Mist.toml from {:?}", toml_path)); - + let toml_content = fs::read_to_string(&toml_path).unwrap_or_else((_) => panic!("Could not read file at {:?}", toml_path)); + MistConfig mut config = toml::from_str(&toml_content).unwrap_or_else((_) => panic!("Failed to parse Mist.toml from {:?}", toml_path)); for pkg in &mut config.packages { *pkg = src.join(&*pkg); } - config.package = src.join(&*config.package); - - let master = modules::Module::new( - config.package.clone(), - &config - ); - + let master = modules::Module::new(config.package.clone(), &config); master.transpile(&out, &mut config); - let elapsed = start.elapsed(); - - println!( - "\x1b[32m\nTranspile successful\x1b[0m in \x1b[34m{:.2?}\x1b[0m", - elapsed - ); - + println!("\x1b[32m\nTranspile successful\x1b[0m in \x1b[34m{:.2?}\x1b[0m", + elapsed); root } -impl modules::Module { - (bool, String) transpile(&self, PathBuf& parent_dir, MistConfig mut& config) { +impl modules::Module +{ + (bool, String) transpile(&self, PathBuf& parent_dir, MistConfig mut& config) + { if !self.path.is_dir() && self.path.extension().and_then((v) => v.to_str()) != Some("mist") { - let file_name = self.path.file_name() - .and_then((s) => s.to_str()) - .expect("Failed to get file name"); - + let file_name = self.path.file_name().and_then((s) => s.to_str()).expect("Failed to get file name"); fs::copy(&self.path, parent_dir.join(&file_name)).expect("Failed to copy SideFile"); - return (true, String::new()); } - let dir = self.output_dir(parent_dir); - let _ = fs::create_dir_all(&dir); - let mut output = String::new(); - let mut child_changed = false; - for child in &self.children { if !config.should_ignore(&child.path) { let out = child.transpile(&dir, config); if out.0 { child_changed = true; } - output.push_str(&out.1); } } - if self.path == config.package { config.main_mods = output.clone(); } else if config.should_ignore(&self.path) { output.push_str(&config.main_mods) } - self.write_transpile(output, parent_dir, child_changed) } - - (bool, String) write_transpile(&self, String output, PathBuf& parent_dir, bool child_changed) { + (bool, String) write_transpile(&self, String output, PathBuf& parent_dir, bool child_changed) + { if self.path.is_dir() { let output_file = self.output_path(parent_dir, &None); - if output.len() == 0 { return (true, String::new()); } - let res = fs::write(&output_file, output); - if res.is_err() { - eprintln!( - "error: failed to write output {}\n {}", + eprintln!("error: failed to write output {}\n {}", output_file.display(), - res.unwrap_err(), - ); - + res.unwrap_err(),); process::exit(1); } - (false, format!("pub mod {};\n", self.name)) } else { let source = match fs::read_to_string(&self.path) { - Ok(s) => s; + Ok(s) => s, Err(e) => { eprintln!("error: failed to read file {}\n {}", self.path.display(), e); - process::exit(1); } }; - let curr_mod_decl = mist_parser::parse_module(&source).expect("Failed parsing module"); - let output_file = self.output_path(parent_dir, &curr_mod_decl); - let should_change = is_source_newer(&self.path, &output_file).expect("Failed to cache"); - if should_change || child_changed { transpile_file(&self.path, &source, output_file, &output, &curr_mod_decl); } - (should_change, if let Some((vis, name)) = &curr_mod_decl { format!("{}mod {};\n", vis.get_rust(), name.get_rust()) } else { @@ -174,141 +145,101 @@ impl modules::Module { } } -std::io::Result is_source_newer(Path& source, Path& output) { +std::io::Result is_source_newer(Path& source, Path& output) +{ if !output.exists() { return Ok(true); } - let source_time = fs::metadata(source)?.modified()?; let output_time = fs::metadata(output)?.modified()?; - Ok(source_time > output_time) } -pub enum TranspileError<'a> { +pub enum TranspileError<'a> +{ Parse(error::ParseError<'a>), - Semantic(Vec) + Semantic(Vec), } -pub Result<(PathBuf, mist_codegen::RustCodegen, String), TranspileError<'a>> - transpile_code<'a>( - PathBuf& path, - str 'a& source, - PathBuf mut output_file, - str& mod_decl, - Option<(mist_parser::ast::Visibility, mist_parser::ast::Identifier)>& curr_mod_decl - ) { - +pub Result<(PathBuf, mist_codegen::RustCodegen, String), TranspileError<'a>> transpile_code<'a>(PathBuf& path, str 'a& source, PathBuf mut output_file, str& mod_decl, Option<(mist_parser::ast::Visibility, mist_parser::ast::Identifier)>& curr_mod_decl) +{ if let Some((_, name)) = &curr_mod_decl { if output_file.file_name().map((v) => v.to_str()).unwrap_or_default() != Some("mod.rs") { if let Some(ext) = output_file.extension().map((e) => e.to_owned()) { let mut new_name = std::ffi::OsString::from(&name.0); - new_name.push("."); new_name.push(ext); - output_file.set_file_name(new_name); } else { output_file.set_file_name(&name.0); } } } - let mut gc = mist_codegen::RustCodegen::new(path.clone()); - let parsed = mist_parser::parse(source).map_err(TranspileError::Parse)?; - for i in &parsed.items { let _ = mist_parser::semantics::check_class_semantics(i).map_err(TranspileError::Semantic)?; } - gc.generate(parsed.mod_attributes); - gc.add(mod_decl); - let output = gc.generate(parsed.items); - Ok((output_file, gc, output)) } -pub void transpile_file( - PathBuf& path, - str& source, - PathBuf output_file, - str& mod_decl, - Option<(mist_parser::ast::Visibility, mist_parser::ast::Identifier)>& curr_mod_decl - ) { - +pub void transpile_file(PathBuf& path, str& source, PathBuf output_file, str& mod_decl, Option<(mist_parser::ast::Visibility, mist_parser::ast::Identifier)>& curr_mod_decl) +{ let (output_file, gc, output) = match transpile_code(path, source, output_file, mod_decl, curr_mod_decl) { - Ok(output) => output; + Ok(output) => output, Err(e) => { decode_err(&e, path); process::exit(1); } }; - let res = fs::write(&output_file, output); - let output_file_map = output_file.with_extension("map.json"); - let res_map = fs::write(&output_file_map, serde_json::to_string(&gc.mapping).unwrap()); - if res_map.is_err() { - eprintln!( - "error: failed to write mapping output {}\n {}", + eprintln!("error: failed to write mapping output {}\n {}", output_file_map.display(), - res.as_ref().unwrap_err(), - ); + res.as_ref().unwrap_err(),); } - if res.is_err() { - eprintln!( - "error: failed to write output {}\n {}", + eprintln!("error: failed to write output {}\n {}", output_file.display(), - res.as_ref().unwrap_err(), - ); + res.as_ref().unwrap_err(),); } - if res_map.is_err() || res.is_err() { process::exit(1); } } -pub void decode_err<'a>(TranspileError<'a>& err, PathBuf& path) { +pub void decode_err<'a>(TranspileError<'a>& err, PathBuf& path) +{ let curr_dir = std::env::current_dir().unwrap(); - match err { TranspileError::Semantic(e_list) => { for e in e_list { - eprintln!( - "\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}", + eprintln!("\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}", path.strip_prefix(&curr_dir).unwrap_or_else(|_| path).as_os_str().display(), e.line, e.column, - e.error_message, - ); + e.error_message,); } } - TranspileError::Parse(e) => { match e { error::ParseError::Ast(e) => { let start_pos = e.span.start_pos().line_col(); - let span = e.span.as_str(); - - eprintln!( - "\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}", + eprintln!("\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}", path.strip_prefix(curr_dir).unwrap_or_else(|_| path).as_os_str().display(), start_pos.0, start_pos.1, e.error_message, span, if span.ends_with("\n") { "" } else { "\n" }, - "^".repeat(span.trim().len()), - ); + "^".repeat(span.trim().len()),); } - error::ParseError::PreAst(e) => { eprintln!("error: parse failed in {}\n{}", path.strip_prefix(curr_dir).unwrap_or_else(|_| path).display(), e); } diff --git a/src/analyzer.mist b/src/analyzer.mist index 59bd4e5..997e48d 100644 --- a/src/analyzer.mist +++ b/src/analyzer.mist @@ -1,3 +1,4 @@ -void main() { +void main() +{ mist_analyzer::start(); } diff --git a/src/main.mist b/src/main.mist index ba7b066..3994119 100644 --- a/src/main.mist +++ b/src/main.mist @@ -1,23 +1,24 @@ use std::process; + use std::env; + use std::fs; + use mist_api::builder; + use mist_api::transpiler; -void main() { +void main() +{ Vec args = env::args().collect(); - if args.len() < 2 { print_usage(); process::exit(1); } - match args[1].as_str() { "run" | "build" | "check" | "r" | "b" | "c" => { let root = transpiler::transpile(); - println!(""); - if builder::build(args, root) { println!("\x1b[32m\nBuild successful\x1b[0m"); } else { @@ -44,41 +45,26 @@ void main() { } } -void print_usage() { +void print_usage() +{ println!("Mist - the mist compiler\n"); println!("󰖟 View our documentation! \x1b[35mhttps://mist.selimaj.dev\x1b[0m"); println!(" Follow us on github! \x1b[35mhttps://github.com/mist-go\x1b[0m\n"); println!("usage:"); println!(" \x1b[36m mist run\x1b[0m,\x1b[36m r\x1b[0m run the project in the current directory\n"); - println!( - " \x1b[36m mist build\x1b[0m,\x1b[36m b\x1b[0m build the project in the current directory\n" - ); - println!( - " \x1b[36m mist transpile\x1b[0m,\x1b[36m t\x1b[0m transpile the project in the current directory\n" - ); - println!( - " \x1b[36m mist check\x1b[0m,\x1b[36m c\x1b[0m check the project in the current directory\n" - ); - println!( - " \x1b[36m mist init\x1b[0m initialize a project in the current folder\n" - ); + println!(" \x1b[36m mist build\x1b[0m,\x1b[36m b\x1b[0m build the project in the current directory\n"); + println!(" \x1b[36m mist transpile\x1b[0m,\x1b[36m t\x1b[0m transpile the project in the current directory\n"); + println!(" \x1b[36m mist check\x1b[0m,\x1b[36m c\x1b[0m check the project in the current directory\n"); + println!(" \x1b[36m mist init\x1b[0m initialize a project in the current folder\n"); println!(" \x1b[36m mist version \x1b[0m print the compiler version\n"); println!(" \x1b[36m mist help\x1b[0m print this message\n"); } -void init_project(Vec mut args) { +void init_project(Vec mut args) +{ args.remove(0); - - process::Command::new("cargo") - .args(args) - .stdout(process::Stdio::inherit()) - .stderr(process::Stdio::inherit()) - .stdin(process::Stdio::inherit()) - .spawn() - .expect("Failed to run cargo").wait().expect("Unable to wait"); - + process::Command::new("cargo").args(args).stdout(process::Stdio::inherit()).stderr(process::Stdio::inherit()).stdin(process::Stdio::inherit()).spawn().expect("Failed to run cargo").wait().expect("Unable to wait"); bool is_lib = fs::metadata("src/lib.rs").is_ok(); - if is_lib { fs::remove_file("src/lib.rs").expect("Failed to remove src/lib.rs"); fs::write("src/lib.mist", "fn test() {\n}").expect("Failed to create src/lib.mist"); @@ -86,20 +72,17 @@ void init_project(Vec mut args) { fs::remove_file("src/main.rs").expect("Failed to remove src/main.rs"); fs::write("src/main.mist", "fn main() {\n println!(\"Hello, World!\");\n}\n").expect("Failed to create src/main.mist"); } - inject_mist_target(is_lib); - println!("\n\x1b[34minfo\x1b[0m: Please open Cargo.toml and adjust `\x1b[35mname\x1b[0m = ` as needed, Thank you for using Mist!\n"); } -void inject_mist_target(bool is_lib) { +void inject_mist_target(bool is_lib) +{ String toml_content = fs::read_to_string("Cargo.toml").expect("Failed to read Cargo.toml"); - str& inject = if is_lib { "\n[lib]\nname = \"my_lib\"\npath = \".mist/src/lib.rs\"\n" } else { "\n[[bin]]\nname = \"my_bin\"\npath = \".mist/src/main.rs\"\n" }; - - fs::write("Cargo.toml", toml_content+inject).expect("Failed to inject to Cargo.toml"); -} \ No newline at end of file + fs::write("Cargo.toml", toml_content + inject).expect("Failed to inject to Cargo.toml"); +}