From 5648c1da610a315680cb120ce69667a169f129b6 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 18 May 2026 13:58:59 +0200 Subject: [PATCH 01/23] Spanned --- parser/src/ast/mod.rs | 9 ++++++++- parser/src/parser/mod.rs | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/parser/src/ast/mod.rs b/parser/src/ast/mod.rs index ad0b287..cea2418 100644 --- a/parser/src/ast/mod.rs +++ b/parser/src/ast/mod.rs @@ -17,6 +17,9 @@ pub struct Identifier(pub String); #[derive(Debug, Clone, Serialize, Default)] pub struct ParamList(pub Vec); +#[derive(Debug, Clone, Serialize)] +pub struct TypeExpr(pub TypeExprKind, pub Vec); + #[derive(Debug, Clone, Serialize)] pub enum TypePostfix { Ref, @@ -34,7 +37,11 @@ pub enum TypeExprKind { } #[derive(Debug, Clone, Serialize)] -pub struct TypeExpr(pub TypeExprKind, pub Vec); +pub struct Spanned { + pub line: usize, + pub column: usize, + pub item: T, +} impl TypeExpr { pub fn no_px(kind: TypeExprKind) -> Self { diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index d7dad09..08f20b8 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -1,7 +1,7 @@ pub mod common; pub mod items; -use crate::Rule; +use crate::{Rule, ast::Spanned}; pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { let consumed = pairs @@ -27,3 +27,19 @@ pub fn consume_rule<'a>( if consumed { pairs.next() } else { None } } + +impl<'a, T: TryFrom>> TryFrom> + for Spanned +{ + type Error = T::Error; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let span = pair.as_span().start_pos().line_col(); + + Ok(Self { + line: span.0, + column: span.1, + item: pair.try_into()?, + }) + } +} From a88ff4c8dd3ecca3de4d01f877ad4d7104117d86 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 18 May 2026 14:42:41 +0200 Subject: [PATCH 02/23] Spanned impl --- parser/src/ast/top_level.rs | 2 +- parser/src/parser/items/mod.rs | 5 +---- parser/src/parser/mod.rs | 25 +++++++++++++++++++++---- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/parser/src/ast/top_level.rs b/parser/src/ast/top_level.rs index 04644ca..1771fb6 100644 --- a/parser/src/ast/top_level.rs +++ b/parser/src/ast/top_level.rs @@ -22,7 +22,7 @@ pub enum Attribute { } #[derive(Debug, Clone, Serialize)] -pub struct TopLevel(pub TopLevelKind, pub Vec); +pub struct TopLevel(pub Spanned, pub Vec); #[derive(Debug, Clone, Serialize)] pub enum TopLevelKind { diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 229ea88..8277660 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -21,10 +21,7 @@ impl<'a> TryFrom> for TopLevel { let attributes = collect_recovered(inner.next().unwrap().into_inner()); ast_expr!(TopLevel( - inner - .next() - .map(TopLevelKind::try_from) - .unwrap_or(Ok(TopLevelKind::ModAttribute)), + inner.next().map(Spanned::try_from).unwrap(), attributes, )) } diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index 08f20b8..6d1ef65 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -1,7 +1,7 @@ pub mod common; pub mod items; -use crate::{Rule, ast::Spanned}; +use crate::{Rule, ast::Spanned, error::AstError}; pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { let consumed = pairs @@ -28,10 +28,10 @@ pub fn consume_rule<'a>( if consumed { pairs.next() } else { None } } -impl<'a, T: TryFrom>> TryFrom> - for Spanned +impl<'a, T: TryFrom, Error = AstError<'a, T>>> + TryFrom> for Spanned { - type Error = T::Error; + type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let span = pair.as_span().start_pos().line_col(); @@ -43,3 +43,20 @@ impl<'a, T: TryFrom>> TryFrom From> for AstError<'a, Spanned> { + fn from(value: AstError<'a, T>) -> Self { + let span = value.span.start_pos().line_col(); + + Self { + span: value.span, + error_code: value.error_code, + error_message: value.error_message, + recovered: value.recovered.map(|v| Spanned { + line: span.0, + column: span.1, + item: v, + }), + } + } +} From d1330500b2a788d102cdc510170ef02394135e13 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 18 May 2026 21:40:01 +0200 Subject: [PATCH 03/23] Spanned --- parser/src/parser/mod.rs | 28 ++++++++++------------------ src/codegen.rs | 37 ++++++++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index 6d1ef65..2e73885 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -39,24 +39,16 @@ impl<'a, T: TryFrom, Error = AstError<'a, T>>> Ok(Self { line: span.0, column: span.1, - item: pair.try_into()?, + item: pair.try_into().map_err(|err: AstError<'_, T>| AstError { + span: err.span, + error_code: err.error_code, + error_message: err.error_message, + recovered: err.recovered.map(|v| Spanned { + line: span.0, + column: span.1, + item: v, + }), + })?, }) } } - -impl<'a, T> From> for AstError<'a, Spanned> { - fn from(value: AstError<'a, T>) -> Self { - let span = value.span.start_pos().line_col(); - - Self { - span: value.span, - error_code: value.error_code, - error_message: value.error_message, - recovered: value.recovered.map(|v| Spanned { - line: span.0, - column: span.1, - item: v, - }), - } - } -} diff --git a/src/codegen.rs b/src/codegen.rs index 2b44796..500b2a5 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,8 +1,8 @@ use mist_parser::ast::{ Attribute, BinaryOp, Block, ClassItem, EnumItem, ExprPath, ExprPathSegment, Expression, FieldDecl, FunctionDecl, Generic, GenericDecl, Generics, GenericsDecl, Identifier, ImplDecl, - Literal, Path, Pattern, Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind, - TypeExpr, TypeExprKind, TypePostfix, VarDecl, VarDeclStmt, Visibility, + Literal, Path, Pattern, Postfix, Prefix, Spanned, Statement, StatementBranch, TopLevel, + TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, VarDecl, VarDeclStmt, Visibility, }; // --------------------------------------------------------------------------- @@ -88,6 +88,17 @@ impl Default for RustCodegen { // GetRust — pure string production (expressions, types) // --------------------------------------------------------------------------- +impl GetRust for Spanned { + fn get_rust(self) -> String { + format!( + "/* {}:{} */ {}", + self.line, + self.column, + self.item.get_rust() + ) + } +} + impl GetRust for TypeExpr { fn get_rust(self) -> String { get_type_postfixes(self.1) + &self.0.get_rust() @@ -315,6 +326,13 @@ impl GetRust for Vec { // ToRust — output-writing (top-level, statements, blocks) // --------------------------------------------------------------------------- +impl ToRust for Spanned { + fn to_rust(self, cg: &mut RustCodegen) { + cg.add_indentedln(&format!("/* {}:{} */", self.line, self.column)); + self.item.to_rust(cg); + } +} + impl ToRust for Block { fn to_rust(self, cg: &mut RustCodegen) { for stmt in self.0 { @@ -325,16 +343,13 @@ impl ToRust for Block { impl ToRust for TopLevel { fn to_rust(self, cg: &mut RustCodegen) { - match self.0 { - TopLevelKind::ModAttribute => { - for attr in self.1 { - cg.addln(&format!("#![{}]", attr.get_rust())); - } + if let TopLevelKind::ModAttribute = self.0.item { + for attr in self.1 { + cg.addln(&format!("#![{}]", attr.get_rust())); } - _ => { - for attr in self.1 { - cg.addln(&format!("#[{}]", attr.get_rust())); - } + } else { + for attr in self.1 { + cg.addln(&format!("#[{}]", attr.get_rust())); } } From c5d8c12c14ea2ea17007b1b0223dc34151dab03d Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 18 May 2026 21:42:22 +0200 Subject: [PATCH 04/23] Fix: visibility spacing --- src/codegen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index 500b2a5..bd83301 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -384,9 +384,9 @@ impl ToRust for TopLevelKind { match self { Self::ModAttribute => {} Self::Import(vis, path) => { - cg.addln(&format!("{} use {};", vis.get_rust(), path.get_rust())) + cg.addln(&format!("{}use {};", vis.get_rust(), path.get_rust())) } - Self::Mod(vis, id) => cg.addln(&format!("{} mod {};", vis.get_rust(), id.get_rust())), + Self::Mod(vis, id) => cg.addln(&format!("{}mod {};", vis.get_rust(), id.get_rust())), Self::FunctionDecl(decl) => decl.to_rust(cg), Self::ImplDecl(impl_) => impl_.to_rust(cg), Self::StructDecl { From 6b314dabf412a2b5c678c86496e3d7be326bf223 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 18 May 2026 21:56:07 +0200 Subject: [PATCH 05/23] Spanned statements --- parser/src/ast/statement.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/src/ast/statement.rs b/parser/src/ast/statement.rs index 8ae23e9..22375f4 100644 --- a/parser/src/ast/statement.rs +++ b/parser/src/ast/statement.rs @@ -3,7 +3,7 @@ use serde::Serialize; use super::*; #[derive(Debug, Clone, Serialize, Default)] -pub struct Block(pub Vec); +pub struct Block(pub Vec>); #[derive(Debug, Clone, Serialize)] pub enum Statement { From 5e8946a1264624a7dfe2cfe04b595506a55e92c1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 00:40:28 +0200 Subject: [PATCH 06/23] Mapping --- parser/src/lib.rs | 1 + parser/src/rev_mapper/grammar.pest | 9 ++++++++ parser/src/rev_mapper/mod.rs | 37 ++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 parser/src/rev_mapper/grammar.pest create mode 100644 parser/src/rev_mapper/mod.rs diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 867c2ef..0a4824c 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -4,6 +4,7 @@ use pest_derive::Parser; pub mod ast; pub mod error; pub mod parser; +pub mod rev_mapper; use ast::*; diff --git a/parser/src/rev_mapper/grammar.pest b/parser/src/rev_mapper/grammar.pest new file mode 100644 index 0000000..bb8ca35 --- /dev/null +++ b/parser/src/rev_mapper/grammar.pest @@ -0,0 +1,9 @@ +WHITESPACE = _{ " " | "\t" | "\r" | "\n" } + +integer = @{ ASCII_DIGIT+ } + +map = { "/*" ~ integer ~ ":" ~ integer ~ "*/" } + +non_map = { (!map ~ ANY)+ } + +mapping = { map | non_map } diff --git a/parser/src/rev_mapper/mod.rs b/parser/src/rev_mapper/mod.rs new file mode 100644 index 0000000..90fc01e --- /dev/null +++ b/parser/src/rev_mapper/mod.rs @@ -0,0 +1,37 @@ +use std::collections::HashSet; + +use pest::Parser; +use pest_derive::Parser; + +#[derive(Parser)] +#[grammar = "./src/rev_mapper/grammar.pest"] +pub struct MistMapperParser; + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct MistMap(pub usize, pub usize); + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct RustMap(pub usize, pub usize); + +pub fn get_mapping(input: &str) -> HashSet<(RustMap, MistMap)> { + let mut mapping = HashSet::new(); + + let pairs = MistMapperParser::parse(Rule::mapping, input).unwrap(); + + for pair in pairs { + if pair.as_rule() == Rule::map { + let rs = pair.as_span().start_pos().line_col(); + let mut inner = pair.into_inner(); + + mapping.insert(( + RustMap(rs.0, rs.1), + MistMap( + inner.next().unwrap().as_str().parse().unwrap(), + inner.next().unwrap().as_str().parse().unwrap(), + ), + )); + } + } + + mapping +} From 11e408cc17295b558ad4d15134c90d0d115410a8 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 00:46:07 +0200 Subject: [PATCH 07/23] find mapping --- parser/src/rev_mapper/mod.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/parser/src/rev_mapper/mod.rs b/parser/src/rev_mapper/mod.rs index 90fc01e..f648d87 100644 --- a/parser/src/rev_mapper/mod.rs +++ b/parser/src/rev_mapper/mod.rs @@ -7,10 +7,10 @@ use pest_derive::Parser; #[grammar = "./src/rev_mapper/grammar.pest"] pub struct MistMapperParser; -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct MistMap(pub usize, pub usize); -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct RustMap(pub usize, pub usize); pub fn get_mapping(input: &str) -> HashSet<(RustMap, MistMap)> { @@ -35,3 +35,14 @@ pub fn get_mapping(input: &str) -> HashSet<(RustMap, MistMap)> { mapping } + +pub fn find_mapping( + mapping: &HashSet<(RustMap, MistMap)>, + target: &RustMap, +) -> Option<(RustMap, MistMap)> { + mapping + .iter() + .copied() + .filter(|(rust, _)| rust <= target) + .max_by_key(|(rust, _)| *rust) +} From 2b43e0c004b0daf16c009fc24cada8b4425f159c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 01:47:02 +0200 Subject: [PATCH 08/23] Working mapping --- parser/src/rev_mapper/grammar.pest | 6 ++++-- parser/src/rev_mapper/mod.rs | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/parser/src/rev_mapper/grammar.pest b/parser/src/rev_mapper/grammar.pest index bb8ca35..7ef6582 100644 --- a/parser/src/rev_mapper/grammar.pest +++ b/parser/src/rev_mapper/grammar.pest @@ -2,8 +2,10 @@ WHITESPACE = _{ " " | "\t" | "\r" | "\n" } integer = @{ ASCII_DIGIT+ } -map = { "/*" ~ integer ~ ":" ~ integer ~ "*/" } +next_line = { "+" } + +map = { "/*" ~ integer ~ ":" ~ integer ~ next_line? ~ "*/" } non_map = { (!map ~ ANY)+ } -mapping = { map | non_map } +mapping = { SOI ~ (map | non_map)* ~ EOI } diff --git a/parser/src/rev_mapper/mod.rs b/parser/src/rev_mapper/mod.rs index f648d87..ff9fbcf 100644 --- a/parser/src/rev_mapper/mod.rs +++ b/parser/src/rev_mapper/mod.rs @@ -16,18 +16,31 @@ pub struct RustMap(pub usize, pub usize); pub fn get_mapping(input: &str) -> HashSet<(RustMap, MistMap)> { let mut mapping = HashSet::new(); - let pairs = MistMapperParser::parse(Rule::mapping, input).unwrap(); + let pairs = MistMapperParser::parse(Rule::mapping, input) + .unwrap() + .next() + .unwrap() + .into_inner(); for pair in pairs { if pair.as_rule() == Rule::map { let rs = pair.as_span().start_pos().line_col(); let mut inner = pair.into_inner(); + let (line, col) = ( + inner.next().unwrap().as_str().parse().unwrap(), + inner.next().unwrap().as_str().parse().unwrap(), + ); + mapping.insert(( RustMap(rs.0, rs.1), MistMap( - inner.next().unwrap().as_str().parse().unwrap(), - inner.next().unwrap().as_str().parse().unwrap(), + if inner.next().is_some() { + line + } else { + line - 1 + }, + col, ), )); } From 670835a5e737099d012631ff7a489cfa2a012794 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 02:04:37 +0200 Subject: [PATCH 09/23] Added cargo_metadata and renamed compiler module --- Cargo.lock | 64 ++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 6 +-- src/{compiler.rs => transpiler.rs} | 0 4 files changed, 68 insertions(+), 3 deletions(-) rename src/{compiler.rs => transpiler.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index c8d363b..0ecc10b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,39 @@ dependencies = [ "generic-array", ] +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0061da739915fae12ea00e16397555ed4371a6bb285431aab930f61b0aa4ba" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -78,6 +111,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" name = "mist-lang" version = "0.0.2-alpha0" dependencies = [ + "cargo_metadata", "mist-parser", "serde", "serde_json", @@ -154,6 +188,16 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + [[package]] name = "serde" version = "1.0.228" @@ -219,6 +263,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typenum" version = "1.20.0" diff --git a/Cargo.toml b/Cargo.toml index 5b958f4..9fbe48d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ categories = ["compilers"] serde = { version = "1.0.228", features = ["serde_derive"] } serde_json = "1.0.149" mist-parser = { path = "./parser", version = "0.1.1"} +cargo_metadata = "0.23.1" [[bin]] name = "mist" diff --git a/src/main.rs b/src/main.rs index a3a0abe..0532797 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::process::{self, Command}; pub mod codegen; -pub mod compiler; +pub mod transpiler; fn main() { let args: Vec = std::env::args().collect(); @@ -13,10 +13,10 @@ fn main() { match args[1].as_str() { "run" | "build" | "r" | "b" => { - compiler::build(); + transpiler::build(); Command::new("cargo").args(&args[1..]).status().unwrap(); } - "transpile" | "t" => compiler::build(), + "transpile" | "t" => transpiler::build(), "version" | "--version" | "-v" => { println!("mist {}", env!("CARGO_PKG_VERSION")); } diff --git a/src/compiler.rs b/src/transpiler.rs similarity index 100% rename from src/compiler.rs rename to src/transpiler.rs From 49a3186d26b055e9d4b75edaaaaa8dac7fb7e1ef Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 02:58:57 +0200 Subject: [PATCH 10/23] Diagnostic conversion --- src/builder.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 5 ++-- 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/builder.rs diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 0000000..247385d --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,73 @@ +use std::{ + collections::{HashMap, HashSet}, + fs, + process::{Command, Stdio}, +}; + +use cargo_metadata::Message; +use mist_parser::rev_mapper::{MistMap, RustMap, find_mapping, get_mapping}; + +#[derive(Debug, Clone)] +pub struct MistDiagnosticMessage { + pub message: String, + pub src_path: String, + pub line: usize, + pub column: usize, +} + +#[derive(Debug, Clone)] +pub enum MistDiagnostic { + Error(MistDiagnosticMessage), +} + +pub fn build(mut args: Vec) -> Result, Vec> { + args.remove(0); + args.insert(1, "--message-format=json".to_string()); + + let mut command = Command::new("cargo") + .args(args) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + + let reader = std::io::BufReader::new(command.stdout.take().unwrap()); + + let mut diagnostics = Vec::new(); + + let mut mapping: HashMap> = HashMap::new(); + + for message in cargo_metadata::Message::parse_stream(reader) { + match message { + Ok(Message::CompilerMessage(msg)) => { + let file_name = msg.target.src_path.as_str().to_string().clone(); + + let map = mapping + .entry(file_name.clone()) + .or_insert_with(|| get_mapping(&fs::read_to_string(file_name).unwrap())); + + for span in msg.message.spans { + let mist_span = + find_mapping(&map, &RustMap(span.line_end, span.column_start)).unwrap(); + + diagnostics.push(MistDiagnostic::Error(MistDiagnosticMessage { + message: span.label.unwrap_or(msg.message.message.clone()), + src_path: span.file_name, + line: mist_span.1.0, + column: mist_span.1.1, + })); + } + } + + Ok(Message::BuildFinished(finish)) => { + if finish.success { + return Ok(diagnostics); + } else { + return Err(diagnostics); + } + } + _ => {} + } + } + + Ok(diagnostics) +} diff --git a/src/main.rs b/src/main.rs index 0532797..db15837 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ -use std::process::{self, Command}; +use std::process::{self}; +pub mod builder; pub mod codegen; pub mod transpiler; @@ -14,7 +15,7 @@ fn main() { match args[1].as_str() { "run" | "build" | "r" | "b" => { transpiler::build(); - Command::new("cargo").args(&args[1..]).status().unwrap(); + builder::build(args).unwrap(); } "transpile" | "t" => transpiler::build(), "version" | "--version" | "-v" => { From eb84103ed635fb7a17694b2bcab38565fb4f68b5 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 03:24:12 +0200 Subject: [PATCH 11/23] Improved diagnostic conversion --- mist-test/src/main.mist | 2 +- src/builder.rs | 53 +++++++++++++++++++++++++++++++++++++++-- src/main.rs | 9 +++++-- src/transpiler.rs | 10 ++++---- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index 853e686..118b6bc 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -11,5 +11,5 @@ void main() { // statistics::register(&mut app_instance); app_instance.boot(); - app_instance.run(); + app_instance.rund(); } \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index 247385d..bde2883 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -7,6 +7,8 @@ use std::{ use cargo_metadata::Message; use mist_parser::rev_mapper::{MistMap, RustMap, find_mapping, get_mapping}; +use crate::transpiler::Config; + #[derive(Debug, Clone)] pub struct MistDiagnosticMessage { pub message: String, @@ -20,7 +22,10 @@ pub enum MistDiagnostic { Error(MistDiagnosticMessage), } -pub fn build(mut args: Vec) -> Result, Vec> { +pub fn build( + mut args: Vec, + config: Config, +) -> Result, Vec> { args.remove(0); args.insert(1, "--message-format=json".to_string()); @@ -49,9 +54,14 @@ pub fn build(mut args: Vec) -> Result, Vec) -> Result, Vec) { + 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{}", + msg.src_path, + msg.line + 1, + msg.column, + msg.message, + line.unwrap_or_default(), + ) + } + } + } +} + +pub fn get_line( + files: &mut HashMap>, + msg: &MistDiagnosticMessage, +) -> Option { + let src_path = msg.src_path.clone(); + + let lines = files.entry(src_path.clone()).or_insert_with(|| { + fs::read_to_string(src_path) + .unwrap() + .lines() + .into_iter() + .map(String::from) + .collect() + }); + + lines.get(msg.line).map(|v| v.trim().to_string()) +} diff --git a/src/main.rs b/src/main.rs index db15837..b8a7188 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,10 +14,15 @@ fn main() { match args[1].as_str() { "run" | "build" | "r" | "b" => { + let config = transpiler::build(); + match builder::build(args, config) { + Ok(diagnostics) => builder::print_diagnostics(diagnostics), + Err(diagnostics) => builder::print_diagnostics(diagnostics), + } + } + "transpile" | "t" => { transpiler::build(); - builder::build(args).unwrap(); } - "transpile" | "t" => transpiler::build(), "version" | "--version" | "-v" => { println!("mist {}", env!("CARGO_PKG_VERSION")); } diff --git a/src/transpiler.rs b/src/transpiler.rs index e1dd733..c53419c 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -9,12 +9,12 @@ use mist_parser::error::ParseError; use serde::Deserialize; #[derive(Deserialize)] -struct Config { - src: String, - output: String, +pub struct Config { + pub src: String, + pub output: String, } -pub fn build() { +pub fn build() -> Config { let start = Instant::now(); // 1. find project root @@ -35,6 +35,8 @@ pub fn build() { let elapsed = start.elapsed(); println!("build finished in {:.2?}", elapsed); + + config } fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { From e30722dde3de209a2fedf2de35eb377fecb2632d Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 03:32:17 +0200 Subject: [PATCH 12/23] Warning --- mist-test/src/main.mist | 2 +- src/builder.rs | 52 +++++++++++++++++++++++++++++++---------- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index 118b6bc..853e686 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -11,5 +11,5 @@ void main() { // statistics::register(&mut app_instance); app_instance.boot(); - app_instance.rund(); + app_instance.run(); } \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index bde2883..787c212 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -20,6 +20,7 @@ pub struct MistDiagnosticMessage { #[derive(Debug, Clone)] pub enum MistDiagnostic { Error(MistDiagnosticMessage), + Warning(MistDiagnosticMessage), } pub fn build( @@ -51,20 +52,34 @@ pub fn build( .or_insert_with(|| get_mapping(&fs::read_to_string(file_name).unwrap())); for span in msg.message.spans { - let mist_span = - find_mapping(&map, &RustMap(span.line_end, span.column_start)).unwrap(); + if span.is_primary { + let mist_span = + find_mapping(&map, &RustMap(span.line_end, span.column_start)).unwrap(); - let mist_file = span - .file_name - .replacen(&config.output, &config.src, 1) - .replace(".rs", ".mist"); + let mist_file = span + .file_name + .replacen(&config.output, &config.src, 1) + .replace(".rs", ".mist"); - diagnostics.push(MistDiagnostic::Error(MistDiagnosticMessage { - message: span.label.unwrap_or(msg.message.message.clone()), - src_path: mist_file, - line: mist_span.1.0, - column: mist_span.1.1, - })); + let mist_msg = MistDiagnosticMessage { + message: span.label.unwrap_or(msg.message.message.clone()), + src_path: mist_file, + line: mist_span.1.0, + column: mist_span.1.1, + }; + + 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)) + } + + _ => {} + } + } } } @@ -99,6 +114,19 @@ pub fn print_diagnostics(diagnostics: Vec) { line.unwrap_or_default(), ) } + + MistDiagnostic::Warning(msg) => { + let line = get_line(&mut files, &msg); + + println!( + "\n{}:{}:{}\n \x1b[33mWarning\x1b[0m: {}\n\t{}", + msg.src_path, + msg.line + 1, + msg.column, + msg.message, + line.unwrap_or_default(), + ) + } } } } From 95ae7b8d5220d9507c1d091ed8847c82c4363658 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 04:35:12 +0200 Subject: [PATCH 13/23] Improved paths, and added rust specific errors --- src/builder.rs | 53 ++++++++++++++++++++++++++++++++--------------- src/main.rs | 5 +++-- src/transpiler.rs | 4 ++-- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 787c212..06a8b22 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,10 +1,11 @@ use std::{ collections::{HashMap, HashSet}, - fs, + env, fs, + path::PathBuf, process::{Command, Stdio}, }; -use cargo_metadata::Message; +use cargo_metadata::{CompilerMessage, Message}; use mist_parser::rev_mapper::{MistMap, RustMap, find_mapping, get_mapping}; use crate::transpiler::Config; @@ -12,7 +13,8 @@ use crate::transpiler::Config; #[derive(Debug, Clone)] pub struct MistDiagnosticMessage { pub message: String, - pub src_path: String, + pub file_path: String, + pub file_name: String, pub line: usize, pub column: usize, } @@ -21,15 +23,19 @@ pub struct MistDiagnosticMessage { pub enum MistDiagnostic { Error(MistDiagnosticMessage), Warning(MistDiagnosticMessage), + Rust(CompilerMessage), } pub fn build( mut args: Vec, config: Config, + root: PathBuf, ) -> Result, Vec> { args.remove(0); args.insert(1, "--message-format=json".to_string()); + let is_root = root == env::current_dir().unwrap(); + let mut command = Command::new("cargo") .args(args) .stdout(Stdio::piped()) @@ -45,25 +51,37 @@ pub fn build( for message in cargo_metadata::Message::parse_stream(reader) { match message { Ok(Message::CompilerMessage(msg)) => { - let file_name = msg.target.src_path.as_str().to_string().clone(); - - let map = mapping - .entry(file_name.clone()) - .or_insert_with(|| get_mapping(&fs::read_to_string(file_name).unwrap())); - - for span in msg.message.spans { + for span in &msg.message.spans { if span.is_primary { - let mist_span = - find_mapping(&map, &RustMap(span.line_end, span.column_start)).unwrap(); + let file_name = span.file_name.clone(); let mist_file = span .file_name .replacen(&config.output, &config.src, 1) .replace(".rs", ".mist"); + let mist_path = root.join(&mist_file); + + if !fs::exists(&mist_path).unwrap() { + diagnostics.push(MistDiagnostic::Rust(msg)); + break; + } + + let map = mapping.entry(file_name.clone()).or_insert_with(|| { + get_mapping(&fs::read_to_string(file_name).unwrap()) + }); + + let mist_span = + find_mapping(&map, &RustMap(span.line_end, span.column_start)).unwrap(); + let mist_msg = MistDiagnosticMessage { - message: span.label.unwrap_or(msg.message.message.clone()), - src_path: mist_file, + message: span.label.clone().unwrap_or(msg.message.message.clone()), + file_path: mist_path.to_string_lossy().to_string(), + file_name: if is_root { + mist_file + } else { + mist_path.to_string_lossy().to_string() + }, line: mist_span.1.0, column: mist_span.1.1, }; @@ -107,7 +125,7 @@ pub fn print_diagnostics(diagnostics: Vec) { println!( "\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}", - msg.src_path, + msg.file_name, msg.line + 1, msg.column, msg.message, @@ -120,13 +138,14 @@ pub fn print_diagnostics(diagnostics: Vec) { println!( "\n{}:{}:{}\n \x1b[33mWarning\x1b[0m: {}\n\t{}", - msg.src_path, + msg.file_name, msg.line + 1, msg.column, msg.message, line.unwrap_or_default(), ) } + MistDiagnostic::Rust(rs) => println!("{rs}"), } } } @@ -135,7 +154,7 @@ pub fn get_line( files: &mut HashMap>, msg: &MistDiagnosticMessage, ) -> Option { - let src_path = msg.src_path.clone(); + let src_path = msg.file_path.clone(); let lines = files.entry(src_path.clone()).or_insert_with(|| { fs::read_to_string(src_path) diff --git a/src/main.rs b/src/main.rs index b8a7188..383abe4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,8 +14,9 @@ fn main() { match args[1].as_str() { "run" | "build" | "r" | "b" => { - let config = transpiler::build(); - match builder::build(args, config) { + let (config, root) = transpiler::build(); + + match builder::build(args, config, root) { Ok(diagnostics) => builder::print_diagnostics(diagnostics), Err(diagnostics) => builder::print_diagnostics(diagnostics), } diff --git a/src/transpiler.rs b/src/transpiler.rs index c53419c..fbb935d 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -14,7 +14,7 @@ pub struct Config { pub output: String, } -pub fn build() -> Config { +pub fn build() -> (Config, PathBuf) { let start = Instant::now(); // 1. find project root @@ -36,7 +36,7 @@ pub fn build() -> Config { println!("build finished in {:.2?}", elapsed); - config + (config, root) } fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { From 4e98257438b44d8495a5aa1c0014ddbea6d47506 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 04:36:35 +0200 Subject: [PATCH 14/23] Improved paths --- src/builder.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 06a8b22..0dbfd29 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -13,7 +13,7 @@ use crate::transpiler::Config; #[derive(Debug, Clone)] pub struct MistDiagnosticMessage { pub message: String, - pub file_path: String, + pub file_path: PathBuf, pub file_name: String, pub line: usize, pub column: usize, @@ -76,12 +76,12 @@ pub fn build( let mist_msg = MistDiagnosticMessage { message: span.label.clone().unwrap_or(msg.message.message.clone()), - file_path: mist_path.to_string_lossy().to_string(), file_name: if is_root { mist_file } else { mist_path.to_string_lossy().to_string() }, + file_path: mist_path, line: mist_span.1.0, column: mist_span.1.1, }; @@ -151,7 +151,7 @@ pub fn print_diagnostics(diagnostics: Vec) { } pub fn get_line( - files: &mut HashMap>, + files: &mut HashMap>, msg: &MistDiagnosticMessage, ) -> Option { let src_path = msg.file_path.clone(); From 8343740b11eef44f58f8a7de16aecead7135627d Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 04:40:33 +0200 Subject: [PATCH 15/23] Fixed build error on inner dir --- mist-test/src/main.mist | 2 ++ src/builder.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index 853e686..d80df7d 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -7,6 +7,8 @@ pub mod event; void main() { var mut app_instance = new app::Application("mist-app"); + i32 bro; + // greeting::register(&mut app_instance); // statistics::register(&mut app_instance); diff --git a/src/builder.rs b/src/builder.rs index 0dbfd29..e2e02d1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,12 +1,12 @@ use std::{ - collections::{HashMap, HashSet}, + collections::HashMap, env, fs, path::PathBuf, process::{Command, Stdio}, }; use cargo_metadata::{CompilerMessage, Message}; -use mist_parser::rev_mapper::{MistMap, RustMap, find_mapping, get_mapping}; +use mist_parser::rev_mapper::{RustMap, find_mapping, get_mapping}; use crate::transpiler::Config; @@ -46,14 +46,14 @@ pub fn build( let mut diagnostics = Vec::new(); - let mut mapping: HashMap> = HashMap::new(); + let mut mapping = HashMap::new(); for message in cargo_metadata::Message::parse_stream(reader) { match message { Ok(Message::CompilerMessage(msg)) => { for span in &msg.message.spans { if span.is_primary { - let file_name = span.file_name.clone(); + let rust_path = root.join(&span.file_name); let mist_file = span .file_name @@ -67,8 +67,8 @@ pub fn build( break; } - let map = mapping.entry(file_name.clone()).or_insert_with(|| { - get_mapping(&fs::read_to_string(file_name).unwrap()) + let map = mapping.entry(rust_path.clone()).or_insert_with(|| { + get_mapping(&fs::read_to_string(rust_path).unwrap()) }); let mist_span = From ffe868e0cd6605a88c84fa4e126a73bf6b298889 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 05:08:27 +0200 Subject: [PATCH 16/23] Fixed build stdout --- mist-test/src/main.mist | 2 -- src/builder.rs | 20 ++++++++------------ src/main.rs | 8 ++++---- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index d80df7d..853e686 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -7,8 +7,6 @@ pub mod event; void main() { var mut app_instance = new app::Application("mist-app"); - i32 bro; - // greeting::register(&mut app_instance); // statistics::register(&mut app_instance); diff --git a/src/builder.rs b/src/builder.rs index e2e02d1..8ab24bf 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -26,11 +26,7 @@ pub enum MistDiagnostic { Rust(CompilerMessage), } -pub fn build( - mut args: Vec, - config: Config, - root: PathBuf, -) -> Result, Vec> { +pub fn build(mut args: Vec, config: Config, root: PathBuf) -> bool { args.remove(0); args.insert(1, "--message-format=json".to_string()); @@ -39,6 +35,8 @@ pub fn build( let mut command = Command::new("cargo") .args(args) .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .stdin(Stdio::inherit()) .spawn() .unwrap(); @@ -102,20 +100,18 @@ pub fn build( } Ok(Message::BuildFinished(finish)) => { - if finish.success { - return Ok(diagnostics); - } else { - return Err(diagnostics); - } + print_diagnostics(&diagnostics); + return finish.success; } + Ok(Message::TextLine(text)) => println!("{text}"), _ => {} } } - Ok(diagnostics) + false } -pub fn print_diagnostics(diagnostics: Vec) { +pub fn print_diagnostics(diagnostics: &Vec) { let mut files = HashMap::new(); for diag in diagnostics { diff --git a/src/main.rs b/src/main.rs index 383abe4..83d1e8f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,10 +15,10 @@ fn main() { match args[1].as_str() { "run" | "build" | "r" | "b" => { let (config, root) = transpiler::build(); - - match builder::build(args, config, root) { - Ok(diagnostics) => builder::print_diagnostics(diagnostics), - Err(diagnostics) => builder::print_diagnostics(diagnostics), + if builder::build(args, config, root) { + println!("\x1b[32m\nBuild successful\x1b[0m"); + } else { + println!("\x1b[31m\nBuild failed\x1b[0m"); } } "transpile" | "t" => { From bfd768a1620ee17c4cbe9b7c4debe5249888ff9b Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 05:20:16 +0200 Subject: [PATCH 17/23] Working app stdout --- src/builder.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 8ab24bf..57e5a89 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -40,13 +40,13 @@ pub fn build(mut args: Vec, config: Config, root: PathBuf) -> bool { .spawn() .unwrap(); - let reader = std::io::BufReader::new(command.stdout.take().unwrap()); + let mut reader = std::io::BufReader::new(command.stdout.take().unwrap()); let mut diagnostics = Vec::new(); let mut mapping = HashMap::new(); - for message in cargo_metadata::Message::parse_stream(reader) { + for message in cargo_metadata::Message::parse_stream(&mut reader) { match message { Ok(Message::CompilerMessage(msg)) => { for span in &msg.message.spans { @@ -101,8 +101,17 @@ pub fn build(mut args: Vec, config: Config, root: PathBuf) -> bool { 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).unwrap(); + + command.wait().unwrap(); + return finish.success; } + Ok(Message::TextLine(text)) => println!("{text}"), _ => {} } From 1b4c925f9f6002bac8adb9057ed3b9fa59c02f7d Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 05:24:59 +0200 Subject: [PATCH 18/23] Improved transpiler output --- src/main.rs | 1 + src/transpiler.rs | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 83d1e8f..099000e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ fn main() { match args[1].as_str() { "run" | "build" | "r" | "b" => { let (config, root) = transpiler::build(); + println!(""); if builder::build(args, config, root) { println!("\x1b[32m\nBuild successful\x1b[0m"); } else { diff --git a/src/transpiler.rs b/src/transpiler.rs index fbb935d..e188fe7 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -17,14 +17,10 @@ pub struct Config { pub fn build() -> (Config, PathBuf) { let start = Instant::now(); - // 1. find project root let root = find_project_root().unwrap_or_else(|| { panic!("error: could not find project root (mist.json)"); }); - println!("mistc build ({})", root.display()); - - // 2. load config let config = load_config(&root); let src_dir = root.join(&config.src); @@ -34,7 +30,7 @@ pub fn build() -> (Config, PathBuf) { let elapsed = start.elapsed(); - println!("build finished in {:.2?}", elapsed); + println!("\x1b[32m\nTranspile successful\x1b[0m in \x1b[34m{:.2?}\x1b[0m", elapsed); (config, root) } From 6412daa5143910e121f0938a2a04f1e0e0d5d0ce Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 05:28:14 +0200 Subject: [PATCH 19/23] Dramatically improved transpile times by caching --- src/transpiler.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/transpiler.rs b/src/transpiler.rs index e188fe7..ec282c2 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -30,7 +30,10 @@ pub fn build() -> (Config, PathBuf) { 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 + ); (config, root) } @@ -69,13 +72,30 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { let relative = path.strip_prefix(base_src).unwrap(); + // Handle non-mist files with a cache check if path.extension().and_then(|e| e.to_str()) != Some("mist") { - fs::copy(&path, out_dir.join(relative)).expect("Failed to copy non-mist file"); + let dest_path = out_dir.join(relative); + + // Create parent directories for static assets if needed + if let Some(parent) = dest_path.parent() { + let _ = fs::create_dir_all(parent); + } + + if should_skip(&path, &dest_path) { + continue; + } + + fs::copy(&path, dest_path).expect("Failed to copy non-mist file"); continue; } let output_path = out_dir.join(relative).with_extension("rs"); + // Cache layer: Skip if the generated .rs file is newer than the .mist source + if should_skip(&path, &output_path) { + continue; + } + // create parent directories if let Some(parent) = output_path.parent() { if let Err(e) = fs::create_dir_all(parent) { @@ -145,6 +165,15 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { } } +fn should_skip(source: &Path, output: &Path) -> bool { + if let (Ok(src_meta), Ok(out_meta)) = (fs::metadata(source), fs::metadata(output)) { + if let (Ok(src_time), Ok(out_time)) = (src_meta.modified(), out_meta.modified()) { + return out_time >= src_time; + } + } + false +} + pub fn find_project_root() -> Option { let mut dir = std::env::current_dir().ok()?; From 1e191cf3c87a8a8ac5b89cb0ae2002997afe420a Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 06:00:35 +0200 Subject: [PATCH 20/23] Class items, struct items, enum items, mapping --- parser/src/ast/mod.rs | 6 ++++++ parser/src/ast/top_level.rs | 12 ++++++------ parser/src/parser/items/mod.rs | 2 +- src/codegen.rs | 23 +++++++++++++++++------ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/parser/src/ast/mod.rs b/parser/src/ast/mod.rs index cea2418..f1d03f3 100644 --- a/parser/src/ast/mod.rs +++ b/parser/src/ast/mod.rs @@ -59,3 +59,9 @@ impl From for Generic { } } } + +impl Spanned { + pub fn get_comment(&self) -> String { + format!("/* {}:{} */", self.line, self.column) + } +} diff --git a/parser/src/ast/top_level.rs b/parser/src/ast/top_level.rs index 1771fb6..f347c34 100644 --- a/parser/src/ast/top_level.rs +++ b/parser/src/ast/top_level.rs @@ -41,29 +41,29 @@ pub enum TopLevelKind { visibility: Visibility, name: Identifier, generics: GenericsDecl, - fields: Vec, + fields: Vec>, }, StructDecl { visibility: Visibility, name: Identifier, generics: GenericsDecl, - fields: Vec, + fields: Vec>, }, FunctionDecl(FunctionDecl), ClassDecl { visibility: Visibility, name: Identifier, generics: GenericsDecl, - fields: Vec, - constructor: ClassConstructor, + fields: Vec>, + constructor: Spanned, items: Vec, }, } #[derive(Debug, Clone, Serialize)] pub enum ClassItem { - Method(FunctionDecl), - ImplDecl(ImplDecl), + Method(Spanned), + ImplDecl(Spanned), } #[derive(Debug, Clone, Serialize, Default)] diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 8277660..84a961e 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -54,7 +54,7 @@ impl<'a> TryFrom> for TopLevelKind { fields: inner .next() - .map(|pair| collect_recovered::(pair.into_inner())) + .map(|pair| collect_recovered(pair.into_inner())) .transpose() .map(|v| v.unwrap_or_default()), }), diff --git a/src/codegen.rs b/src/codegen.rs index bd83301..6fdd3c9 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -425,7 +425,7 @@ impl ToRust for TopLevelKind { cg.indent += 1; for field in fields { - cg.add_indentedln(&(format!("{}", field.get_rust()) + ",")); + cg.add_indentedln(&(field.get_rust() + ",")); } cg.indent -= 1; @@ -481,7 +481,8 @@ impl ToRust for TopLevelKind { cg.indent += 1; for field in fields.clone() { - cg.add_indentedln(&field.decl.get_rust()); + cg.add_indentedln(&field.get_comment()); + cg.add_indentedln(&field.item.decl.get_rust()); } cg.indent -= 1; @@ -505,6 +506,10 @@ impl ToRust for TopLevelKind { )); cg.indent += 1; + let constructor_comment = constructor.get_comment(); + + let constructor = constructor.item; + let params_str = constructor .params .0 @@ -515,6 +520,7 @@ impl ToRust for TopLevelKind { .join(", "); cg.add_indentedln("#[allow(invalid_value)]"); + cg.add_indentedln(&constructor_comment); cg.add_indentedln(&format!( "{}fn new{}({}) -> Self {{", constructor.visibility.clone().get_rust(), @@ -526,10 +532,14 @@ impl ToRust for TopLevelKind { cg.add_indentedln("let mut this: Self = unsafe { std::mem::MaybeUninit::::zeroed().assume_init() };"); for field in fields { - if let Some(init) = field.init { + let comment = field.get_comment(); + + if let Some(init) = field.item.init { + cg.add_indentedln(&comment); + cg.add_indentedln(&format!( "this.{} = {};", - field.decl.name.get_rust(), + field.item.decl.name.get_rust(), init.get_rust() )); } @@ -552,6 +562,7 @@ impl ToRust for TopLevelKind { cg.add_indentedln("}\n"); // Constructor function + cg.add_indentedln(&constructor_comment); cg.add_indentedln(&format!( "{}fn construct_class{}(&mut self, {}) {{", constructor.visibility.get_rust(), @@ -580,8 +591,8 @@ impl ToRust for TopLevelKind { ClassItem::ImplDecl(impl_) => { let mut impl_ = impl_.clone(); - impl_.trait_ = Some(impl_.target); - impl_.target = + impl_.item.trait_ = Some(impl_.item.target); + impl_.item.target = TypeExpr(TypeExprKind::Path(Path(vec![name.clone()])), Vec::new()); impl_.to_rust(cg); From fd7455c71ebc13e5aed1ac541ddb0497d9f1ff01 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 06:06:04 +0200 Subject: [PATCH 21/23] Fixed traits --- parser/src/ast/top_level.rs | 2 +- parser/src/parser/items/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parser/src/ast/top_level.rs b/parser/src/ast/top_level.rs index f347c34..110e6e9 100644 --- a/parser/src/ast/top_level.rs +++ b/parser/src/ast/top_level.rs @@ -35,7 +35,7 @@ pub enum TopLevelKind { name: Identifier, generics: GenericsDecl, requirements: Vec, - items: Vec, + items: Vec>, }, EnumDecl { visibility: Visibility, diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 84a961e..fe45403 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -8,7 +8,7 @@ use crate::{ Rule, ast::*, ast_expr, - error::{AstError, AstResult, IntoErr, collect_recovered}, + error::{AstError, IntoErr, collect_recovered}, parser::consume_rule, }; @@ -113,7 +113,7 @@ impl<'a> TryFrom> for TopLevelKind { .transpose() .map(|v| v.unwrap_or_default()), - items: Ok(Vec::new()) as AstResult<'_, Vec<_>>, + items: collect_recovered(&mut inner), }), _ => AstError::bug_unimplemented(pair), From 9d051c68e94ef9cb7f2023e49542477f77967a0c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 06:11:52 +0200 Subject: [PATCH 22/23] Impl spanned functions --- mist-test/src/logger.mist | 10 ++++++++-- parser/src/ast/top_level.rs | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mist-test/src/logger.mist b/mist-test/src/logger.mist index 7854ab9..ab194cd 100644 --- a/mist-test/src/logger.mist +++ b/mist-test/src/logger.mist @@ -2,7 +2,7 @@ use ; use ; pub trait TestLogging: fmt::Display { - String get(); + String get(self*); } pub enum LogLevel { @@ -29,6 +29,12 @@ impl fmt::Display for LogLevel { } } +impl TestLogging for LogLevel { + String get(self*) { + return format!("{self}"); + } +} + pub class Logger { String prefix; @@ -55,7 +61,7 @@ pub class Logger { } LogLevel::Warning => { - println!("{level} {} {}", self.prefix, message); + println!("{} {} {}", level.get(), self.prefix, message); } LogLevel::Error => { diff --git a/parser/src/ast/top_level.rs b/parser/src/ast/top_level.rs index 110e6e9..8de8531 100644 --- a/parser/src/ast/top_level.rs +++ b/parser/src/ast/top_level.rs @@ -105,7 +105,7 @@ pub struct ImplDecl { pub generics: GenericsDecl, pub target: TypeExpr, pub trait_: Option, - pub methods: Vec, + pub methods: Vec>, } #[derive(Debug, Clone, Serialize)] From a5ccd9651a899d687b7cecb79364cddd215d6025 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 19 May 2026 06:24:35 +0200 Subject: [PATCH 23/23] Added check command and updated help --- src/main.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 099000e..d99e832 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ fn main() { } match args[1].as_str() { - "run" | "build" | "r" | "b" => { + "run" | "build" | "check" | "r" | "b" | "c" => { let (config, root) = transpiler::build(); println!(""); if builder::build(args, config, root) { @@ -44,12 +44,15 @@ fn print_usage() { 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 run the project in the current directory\n"); + 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 build the project in the current directory\n" + " \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 transpile the project in the current directory\n" + " \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 version \x1b[0m print the compiler version\n"); println!(" \x1b[36m mist help\x1b[0m print this message\n");