From c22ec4e0dbe325cf03426e3f268333e1af7acaf6 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 13 Apr 2026 15:30:59 +0200 Subject: [PATCH] Better compiler --- .gitignore | 2 + src/compiler.rs | 104 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 25 +++------- test/mist.toml | 7 +++ test/{ => src}/main.ms | 0 5 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 src/compiler.rs create mode 100644 test/mist.toml rename test/{ => src}/main.ms (100%) diff --git a/.gitignore b/.gitignore index 0728338..7e6aa69 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ target # Added by cargo /target + +/test/build \ No newline at end of file diff --git a/src/compiler.rs b/src/compiler.rs new file mode 100644 index 0000000..c74ab7a --- /dev/null +++ b/src/compiler.rs @@ -0,0 +1,104 @@ +use std::{fs, path::PathBuf, process, time::Instant}; + +use crate::{gogen, parser}; + +pub fn build() { + let start = Instant::now(); + + // 1. find project root + let root = find_project_root().unwrap_or_else(|| { + panic!("error: could not find project root (mist.toml)"); + }); + + println!("mistc build ({})", root.display()); + + // 2. load config + let config = load_config(&root); + + let entry_path = root.join(&config.entry); + let out_dir = root.join(&config.out_dir); + + println!(" → entry: {}", entry_path.display()); + + // 3. read entry file + let source = match fs::read_to_string(&entry_path) { + Ok(s) => s, + Err(e) => { + eprintln!("error: failed to read entry file\n {}", e); + process::exit(1); + } + }; + + println!(" → parsing..."); + + let ast = match parser::parse(&source) { + Ok(ast) => { + println!(" ✓ parsed {} items", ast.statements.len()); + ast + } + Err(e) => { + eprintln!("error: parse failed\n{}", e); + process::exit(1); + } + }; + + println!(" → generating Go code..."); + + let output = gogen::generate(&ast); + + // 4. ensure build dir + if let Err(e) = fs::create_dir_all(&out_dir) { + eprintln!("error: failed to create build dir\n {}", e); + process::exit(1); + } + + let out_file = out_dir.join("main.go"); + + if let Err(e) = fs::write(&out_file, output) { + eprintln!("error: failed to write output\n {}", e); + process::exit(1); + } + + let elapsed = start.elapsed(); + + println!(" ✓ built {}", out_file.display()); + println!("build finished in {:.2?}", elapsed); +} + +pub fn find_project_root() -> Option { + let mut dir = std::env::current_dir().ok()?; + + loop { + if dir.join("mist.toml").exists() { + return Some(dir); + } + + if !dir.pop() { + return None; + } + } +} + +struct Config { + entry: String, + out_dir: String, +} + +fn load_config(root: &std::path::Path) -> Config { + let content = + std::fs::read_to_string(root.join("mist.toml")).expect("failed to read mist.toml"); + + // super minimal parsing (replace later with toml crate) + let entry = extract(&content, "entry").unwrap_or("src/main.ms".into()); + let out_dir = extract(&content, "out_dir").unwrap_or("build".into()); + + Config { entry, out_dir } +} + +fn extract(content: &str, key: &str) -> Option { + content + .lines() + .find(|l| l.trim().starts_with(key)) + .and_then(|l| l.split('=').nth(1)) + .map(|v| v.trim().trim_matches('"').to_string()) +} diff --git a/src/main.rs b/src/main.rs index 91278ec..56fd64a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +pub mod compiler; pub mod errors; pub mod gogen; pub mod parser; @@ -16,11 +17,11 @@ fn main() { match args[1].as_str() { "build" => { - if args.len() < 3 { - eprintln!("error: expected a file path\n usage: mist build "); + if args.len() < 2 { + eprintln!("error: expected a file path\n usage: mist build"); process::exit(1); } - cmd_build(&args[2]); + cmd_build(); } "check" => { if args.len() < 3 { @@ -43,20 +44,8 @@ fn main() { } } -fn cmd_build(path: &str) { - let source = read_ms_file(path); - match parser::parse(&source) { - Ok(ast) => { - println!("parsed {} top-level items", ast.statements.len()); - let contents = gogen::generate(&ast); - fs::write(path.to_string() + ".go", contents).unwrap(); - println!("build successful"); - } - Err(e) => { - eprintln!("parse error:\n{}", e); - process::exit(1); - } - } +pub fn cmd_build() { + compiler::build(); } fn cmd_check(path: &str) { @@ -95,7 +84,7 @@ fn print_usage() { println!("mist - the mist compiler"); println!(); println!("usage:"); - println!(" mist build compile a .ms file to go"); + println!(" mist build compile the project in the current directory"); println!(" mist check parse and validate without compiling"); println!(" mist version print the compiler version"); println!(" mist help print this message"); diff --git a/test/mist.toml b/test/mist.toml new file mode 100644 index 0000000..071051b --- /dev/null +++ b/test/mist.toml @@ -0,0 +1,7 @@ +[package] +name = "myapp" +version = "0.1.0" + +[build] +entry = "src/main.ms" +out_dir = "build" diff --git a/test/main.ms b/test/src/main.ms similarity index 100% rename from test/main.ms rename to test/src/main.ms