Merge pull request #35 from mist-go/errors-and-caching

Errors and caching
This commit is contained in:
2026-05-19 06:36:42 +02:00
committed by GitHub
15 changed files with 476 additions and 59 deletions
Generated
+64
View File
@@ -11,6 +11,39 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.4" version = "1.0.4"
@@ -78,6 +111,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
name = "mist-lang" name = "mist-lang"
version = "0.0.2-alpha0" version = "0.0.2-alpha0"
dependencies = [ dependencies = [
"cargo_metadata",
"mist-parser", "mist-parser",
"serde", "serde",
"serde_json", "serde_json",
@@ -154,6 +188,16 @@ dependencies = [
"proc-macro2", "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]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"
@@ -219,6 +263,26 @@ dependencies = [
"unicode-ident", "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]] [[package]]
name = "typenum" name = "typenum"
version = "1.20.0" version = "1.20.0"
+1
View File
@@ -13,6 +13,7 @@ categories = ["compilers"]
serde = { version = "1.0.228", features = ["serde_derive"] } serde = { version = "1.0.228", features = ["serde_derive"] }
serde_json = "1.0.149" serde_json = "1.0.149"
mist-parser = { path = "./parser", version = "0.1.1"} mist-parser = { path = "./parser", version = "0.1.1"}
cargo_metadata = "0.23.1"
[[bin]] [[bin]]
name = "mist" name = "mist"
+8 -2
View File
@@ -2,7 +2,7 @@ use <std::fmt::Formatter>;
use <std::fmt>; use <std::fmt>;
pub trait TestLogging<T: fmt::Display>: fmt::Display { pub trait TestLogging<T: fmt::Display>: fmt::Display {
String get(); String get(self*);
} }
pub enum LogLevel { pub enum LogLevel {
@@ -29,6 +29,12 @@ impl fmt::Display for LogLevel {
} }
} }
impl TestLogging<LogLevel> for LogLevel {
String get(self*) {
return format!("{self}");
}
}
pub class Logger { pub class Logger {
String prefix; String prefix;
@@ -55,7 +61,7 @@ pub class Logger {
} }
LogLevel::Warning => { LogLevel::Warning => {
println!("{level} {} {}", self.prefix, message); println!("{} {} {}", level.get(), self.prefix, message);
} }
LogLevel::Error => { LogLevel::Error => {
+14 -1
View File
@@ -17,6 +17,9 @@ pub struct Identifier(pub String);
#[derive(Debug, Clone, Serialize, Default)] #[derive(Debug, Clone, Serialize, Default)]
pub struct ParamList(pub Vec<VarDecl>); pub struct ParamList(pub Vec<VarDecl>);
#[derive(Debug, Clone, Serialize)]
pub struct TypeExpr(pub TypeExprKind, pub Vec<TypePostfix>);
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum TypePostfix { pub enum TypePostfix {
Ref, Ref,
@@ -34,7 +37,11 @@ pub enum TypeExprKind {
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct TypeExpr(pub TypeExprKind, pub Vec<TypePostfix>); pub struct Spanned<T> {
pub line: usize,
pub column: usize,
pub item: T,
}
impl TypeExpr { impl TypeExpr {
pub fn no_px(kind: TypeExprKind) -> Self { pub fn no_px(kind: TypeExprKind) -> Self {
@@ -52,3 +59,9 @@ impl From<GenericDecl> for Generic {
} }
} }
} }
impl<T> Spanned<T> {
pub fn get_comment(&self) -> String {
format!("/* {}:{} */", self.line, self.column)
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ use serde::Serialize;
use super::*; use super::*;
#[derive(Debug, Clone, Serialize, Default)] #[derive(Debug, Clone, Serialize, Default)]
pub struct Block(pub Vec<Statement>); pub struct Block(pub Vec<Spanned<Statement>>);
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum Statement { pub enum Statement {
+9 -9
View File
@@ -22,7 +22,7 @@ pub enum Attribute {
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct TopLevel(pub TopLevelKind, pub Vec<Attribute>); pub struct TopLevel(pub Spanned<TopLevelKind>, pub Vec<Attribute>);
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum TopLevelKind { pub enum TopLevelKind {
@@ -35,35 +35,35 @@ pub enum TopLevelKind {
name: Identifier, name: Identifier,
generics: GenericsDecl, generics: GenericsDecl,
requirements: Vec<TypeExpr>, requirements: Vec<TypeExpr>,
items: Vec<FunctionDecl>, items: Vec<Spanned<FunctionDecl>>,
}, },
EnumDecl { EnumDecl {
visibility: Visibility, visibility: Visibility,
name: Identifier, name: Identifier,
generics: GenericsDecl, generics: GenericsDecl,
fields: Vec<EnumItem>, fields: Vec<Spanned<EnumItem>>,
}, },
StructDecl { StructDecl {
visibility: Visibility, visibility: Visibility,
name: Identifier, name: Identifier,
generics: GenericsDecl, generics: GenericsDecl,
fields: Vec<FieldDecl>, fields: Vec<Spanned<FieldDecl>>,
}, },
FunctionDecl(FunctionDecl), FunctionDecl(FunctionDecl),
ClassDecl { ClassDecl {
visibility: Visibility, visibility: Visibility,
name: Identifier, name: Identifier,
generics: GenericsDecl, generics: GenericsDecl,
fields: Vec<FieldDeclStmt>, fields: Vec<Spanned<FieldDeclStmt>>,
constructor: ClassConstructor, constructor: Spanned<ClassConstructor>,
items: Vec<ClassItem>, items: Vec<ClassItem>,
}, },
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum ClassItem { pub enum ClassItem {
Method(FunctionDecl), Method(Spanned<FunctionDecl>),
ImplDecl(ImplDecl), ImplDecl(Spanned<ImplDecl>),
} }
#[derive(Debug, Clone, Serialize, Default)] #[derive(Debug, Clone, Serialize, Default)]
@@ -105,7 +105,7 @@ pub struct ImplDecl {
pub generics: GenericsDecl, pub generics: GenericsDecl,
pub target: TypeExpr, pub target: TypeExpr,
pub trait_: Option<TypeExpr>, pub trait_: Option<TypeExpr>,
pub methods: Vec<FunctionDecl>, pub methods: Vec<Spanned<FunctionDecl>>,
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
+1
View File
@@ -4,6 +4,7 @@ use pest_derive::Parser;
pub mod ast; pub mod ast;
pub mod error; pub mod error;
pub mod parser; pub mod parser;
pub mod rev_mapper;
use ast::*; use ast::*;
+4 -7
View File
@@ -8,7 +8,7 @@ use crate::{
Rule, Rule,
ast::*, ast::*,
ast_expr, ast_expr,
error::{AstError, AstResult, IntoErr, collect_recovered}, error::{AstError, IntoErr, collect_recovered},
parser::consume_rule, parser::consume_rule,
}; };
@@ -21,10 +21,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel {
let attributes = collect_recovered(inner.next().unwrap().into_inner()); let attributes = collect_recovered(inner.next().unwrap().into_inner());
ast_expr!(TopLevel( ast_expr!(TopLevel(
inner inner.next().map(Spanned::try_from).unwrap(),
.next()
.map(TopLevelKind::try_from)
.unwrap_or(Ok(TopLevelKind::ModAttribute)),
attributes, attributes,
)) ))
} }
@@ -57,7 +54,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
fields: inner fields: inner
.next() .next()
.map(|pair| collect_recovered::<FieldDecl, FieldDecl>(pair.into_inner())) .map(|pair| collect_recovered(pair.into_inner()))
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
}), }),
@@ -116,7 +113,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
.transpose() .transpose()
.map(|v| v.unwrap_or_default()), .map(|v| v.unwrap_or_default()),
items: Ok(Vec::new()) as AstResult<'_, Vec<_>>, items: collect_recovered(&mut inner),
}), }),
_ => AstError::bug_unimplemented(pair), _ => AstError::bug_unimplemented(pair),
+26 -1
View File
@@ -1,7 +1,7 @@
pub mod common; pub mod common;
pub mod items; pub mod items;
use crate::Rule; use crate::{Rule, ast::Spanned, error::AstError};
pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool {
let consumed = pairs let consumed = pairs
@@ -27,3 +27,28 @@ pub fn consume_rule<'a>(
if consumed { pairs.next() } else { None } if consumed { pairs.next() } else { None }
} }
impl<'a, T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a, T>>>
TryFrom<pest::iterators::Pair<'a, Rule>> for Spanned<T>
{
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let span = pair.as_span().start_pos().line_col();
Ok(Self {
line: span.0,
column: span.1,
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,
}),
})?,
})
}
}
+11
View File
@@ -0,0 +1,11 @@
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
integer = @{ ASCII_DIGIT+ }
next_line = { "+" }
map = { "/*" ~ integer ~ ":" ~ integer ~ next_line? ~ "*/" }
non_map = { (!map ~ ANY)+ }
mapping = { SOI ~ (map | non_map)* ~ EOI }
+61
View File
@@ -0,0 +1,61 @@
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, PartialOrd, Ord)]
pub struct MistMap(pub usize, pub usize);
#[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)> {
let mut mapping = HashSet::new();
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(
if inner.next().is_some() {
line
} else {
line - 1
},
col,
),
));
}
}
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)
}
+174
View File
@@ -0,0 +1,174 @@
use std::{
collections::HashMap,
env, fs,
path::PathBuf,
process::{Command, Stdio},
};
use cargo_metadata::{CompilerMessage, Message};
use mist_parser::rev_mapper::{RustMap, find_mapping, get_mapping};
use crate::transpiler::Config;
#[derive(Debug, Clone)]
pub struct MistDiagnosticMessage {
pub message: String,
pub file_path: PathBuf,
pub file_name: String,
pub line: usize,
pub column: usize,
}
#[derive(Debug, Clone)]
pub enum MistDiagnostic {
Error(MistDiagnosticMessage),
Warning(MistDiagnosticMessage),
Rust(CompilerMessage),
}
pub fn build(mut args: Vec<String>, config: Config, root: PathBuf) -> bool {
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())
.stderr(Stdio::inherit())
.stdin(Stdio::inherit())
.spawn()
.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(&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 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(rust_path.clone()).or_insert_with(|| {
get_mapping(&fs::read_to_string(rust_path).unwrap())
});
let mist_span =
find_mapping(&map, &RustMap(span.line_end, span.column_start)).unwrap();
let mist_msg = MistDiagnosticMessage {
message: span.label.clone().unwrap_or(msg.message.message.clone()),
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,
};
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).unwrap();
command.wait().unwrap();
return finish.success;
}
Ok(Message::TextLine(text)) => println!("{text}"),
_ => {}
}
}
false
}
pub fn print_diagnostics(diagnostics: &Vec<MistDiagnostic>) {
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.file_name,
msg.line + 1,
msg.column,
msg.message,
line.unwrap_or_default(),
)
}
MistDiagnostic::Warning(msg) => {
let line = get_line(&mut files, &msg);
println!(
"\n{}:{}:{}\n \x1b[33mWarning\x1b[0m: {}\n\t{}",
msg.file_name,
msg.line + 1,
msg.column,
msg.message,
line.unwrap_or_default(),
)
}
MistDiagnostic::Rust(rs) => println!("{rs}"),
}
}
}
pub fn get_line(
files: &mut HashMap<PathBuf, Vec<String>>,
msg: &MistDiagnosticMessage,
) -> Option<String> {
let src_path = msg.file_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())
}
+41 -15
View File
@@ -1,8 +1,8 @@
use mist_parser::ast::{ use mist_parser::ast::{
Attribute, BinaryOp, Block, ClassItem, EnumItem, ExprPath, ExprPathSegment, Expression, Attribute, BinaryOp, Block, ClassItem, EnumItem, ExprPath, ExprPathSegment, Expression,
FieldDecl, FunctionDecl, Generic, GenericDecl, Generics, GenericsDecl, Identifier, ImplDecl, FieldDecl, FunctionDecl, Generic, GenericDecl, Generics, GenericsDecl, Identifier, ImplDecl,
Literal, Path, Pattern, Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind, Literal, Path, Pattern, Postfix, Prefix, Spanned, Statement, StatementBranch, TopLevel,
TypeExpr, TypeExprKind, TypePostfix, VarDecl, VarDeclStmt, Visibility, TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, VarDecl, VarDeclStmt, Visibility,
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -88,6 +88,17 @@ impl Default for RustCodegen {
// GetRust — pure string production (expressions, types) // GetRust — pure string production (expressions, types)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
impl<T: GetRust> GetRust for Spanned<T> {
fn get_rust(self) -> String {
format!(
"/* {}:{} */ {}",
self.line,
self.column,
self.item.get_rust()
)
}
}
impl GetRust for TypeExpr { impl GetRust for TypeExpr {
fn get_rust(self) -> String { fn get_rust(self) -> String {
get_type_postfixes(self.1) + &self.0.get_rust() get_type_postfixes(self.1) + &self.0.get_rust()
@@ -315,6 +326,13 @@ impl GetRust for Vec<Postfix> {
// ToRust — output-writing (top-level, statements, blocks) // ToRust — output-writing (top-level, statements, blocks)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
impl<T: ToRust> ToRust for Spanned<T> {
fn to_rust(self, cg: &mut RustCodegen) {
cg.add_indentedln(&format!("/* {}:{} */", self.line, self.column));
self.item.to_rust(cg);
}
}
impl ToRust for Block { impl ToRust for Block {
fn to_rust(self, cg: &mut RustCodegen) { fn to_rust(self, cg: &mut RustCodegen) {
for stmt in self.0 { for stmt in self.0 {
@@ -325,18 +343,15 @@ impl ToRust for Block {
impl ToRust for TopLevel { impl ToRust for TopLevel {
fn to_rust(self, cg: &mut RustCodegen) { fn to_rust(self, cg: &mut RustCodegen) {
match self.0 { if let TopLevelKind::ModAttribute = self.0.item {
TopLevelKind::ModAttribute => {
for attr in self.1 { for attr in self.1 {
cg.addln(&format!("#![{}]", attr.get_rust())); cg.addln(&format!("#![{}]", attr.get_rust()));
} }
} } else {
_ => {
for attr in self.1 { for attr in self.1 {
cg.addln(&format!("#[{}]", attr.get_rust())); cg.addln(&format!("#[{}]", attr.get_rust()));
} }
} }
}
self.0.to_rust(cg); self.0.to_rust(cg);
} }
@@ -369,9 +384,9 @@ impl ToRust for TopLevelKind {
match self { match self {
Self::ModAttribute => {} Self::ModAttribute => {}
Self::Import(vis, path) => { 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::FunctionDecl(decl) => decl.to_rust(cg),
Self::ImplDecl(impl_) => impl_.to_rust(cg), Self::ImplDecl(impl_) => impl_.to_rust(cg),
Self::StructDecl { Self::StructDecl {
@@ -410,7 +425,7 @@ impl ToRust for TopLevelKind {
cg.indent += 1; cg.indent += 1;
for field in fields { for field in fields {
cg.add_indentedln(&(format!("{}", field.get_rust()) + ",")); cg.add_indentedln(&(field.get_rust() + ","));
} }
cg.indent -= 1; cg.indent -= 1;
@@ -466,7 +481,8 @@ impl ToRust for TopLevelKind {
cg.indent += 1; cg.indent += 1;
for field in fields.clone() { 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; cg.indent -= 1;
@@ -490,6 +506,10 @@ impl ToRust for TopLevelKind {
)); ));
cg.indent += 1; cg.indent += 1;
let constructor_comment = constructor.get_comment();
let constructor = constructor.item;
let params_str = constructor let params_str = constructor
.params .params
.0 .0
@@ -500,6 +520,7 @@ impl ToRust for TopLevelKind {
.join(", "); .join(", ");
cg.add_indentedln("#[allow(invalid_value)]"); cg.add_indentedln("#[allow(invalid_value)]");
cg.add_indentedln(&constructor_comment);
cg.add_indentedln(&format!( cg.add_indentedln(&format!(
"{}fn new{}({}) -> Self {{", "{}fn new{}({}) -> Self {{",
constructor.visibility.clone().get_rust(), constructor.visibility.clone().get_rust(),
@@ -511,10 +532,14 @@ impl ToRust for TopLevelKind {
cg.add_indentedln("let mut this: Self = unsafe { std::mem::MaybeUninit::<Self>::zeroed().assume_init() };"); cg.add_indentedln("let mut this: Self = unsafe { std::mem::MaybeUninit::<Self>::zeroed().assume_init() };");
for field in fields { 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!( cg.add_indentedln(&format!(
"this.{} = {};", "this.{} = {};",
field.decl.name.get_rust(), field.item.decl.name.get_rust(),
init.get_rust() init.get_rust()
)); ));
} }
@@ -537,6 +562,7 @@ impl ToRust for TopLevelKind {
cg.add_indentedln("}\n"); cg.add_indentedln("}\n");
// Constructor function // Constructor function
cg.add_indentedln(&constructor_comment);
cg.add_indentedln(&format!( cg.add_indentedln(&format!(
"{}fn construct_class{}(&mut self, {}) {{", "{}fn construct_class{}(&mut self, {}) {{",
constructor.visibility.get_rust(), constructor.visibility.get_rust(),
@@ -565,8 +591,8 @@ impl ToRust for TopLevelKind {
ClassItem::ImplDecl(impl_) => { ClassItem::ImplDecl(impl_) => {
let mut impl_ = impl_.clone(); let mut impl_ = impl_.clone();
impl_.trait_ = Some(impl_.target); impl_.item.trait_ = Some(impl_.item.target);
impl_.target = impl_.item.target =
TypeExpr(TypeExprKind::Path(Path(vec![name.clone()])), Vec::new()); TypeExpr(TypeExprKind::Path(Path(vec![name.clone()])), Vec::new());
impl_.to_rust(cg); impl_.to_rust(cg);
+20 -9
View File
@@ -1,7 +1,8 @@
use std::process::{self, Command}; use std::process::{self};
pub mod builder;
pub mod codegen; pub mod codegen;
pub mod compiler; pub mod transpiler;
fn main() { fn main() {
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
@@ -12,11 +13,18 @@ fn main() {
} }
match args[1].as_str() { match args[1].as_str() {
"run" | "build" | "r" | "b" => { "run" | "build" | "check" | "r" | "b" | "c" => {
compiler::build(); let (config, root) = transpiler::build();
Command::new("cargo").args(&args[1..]).status().unwrap(); println!("");
if builder::build(args, config, root) {
println!("\x1b[32m\nBuild successful\x1b[0m");
} else {
println!("\x1b[31m\nBuild failed\x1b[0m");
}
}
"transpile" | "t" => {
transpiler::build();
} }
"transpile" | "t" => compiler::build(),
"version" | "--version" | "-v" => { "version" | "--version" | "-v" => {
println!("mist {}", env!("CARGO_PKG_VERSION")); println!("mist {}", env!("CARGO_PKG_VERSION"));
} }
@@ -36,12 +44,15 @@ fn print_usage() {
println!("󰖟 View our documentation! \x1b[35mhttps://mist.selimaj.dev\x1b[0m"); 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!(" Follow us on github! \x1b[35mhttps://github.com/mist-go\x1b[0m\n");
println!("usage:"); 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!( 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!( 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 version \x1b[0m print the compiler version\n");
println!(" \x1b[36m mist help\x1b[0m print this message\n"); println!(" \x1b[36m mist help\x1b[0m print this message\n");
+37 -10
View File
@@ -9,22 +9,18 @@ use mist_parser::error::ParseError;
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize)] #[derive(Deserialize)]
struct Config { pub struct Config {
src: String, pub src: String,
output: String, pub output: String,
} }
pub fn build() { pub fn build() -> (Config, PathBuf) {
let start = Instant::now(); let start = Instant::now();
// 1. find project root
let root = find_project_root().unwrap_or_else(|| { let root = find_project_root().unwrap_or_else(|| {
panic!("error: could not find project root (mist.json)"); panic!("error: could not find project root (mist.json)");
}); });
println!("mistc build ({})", root.display());
// 2. load config
let config = load_config(&root); let config = load_config(&root);
let src_dir = root.join(&config.src); let src_dir = root.join(&config.src);
@@ -34,7 +30,12 @@ pub fn build() {
let elapsed = start.elapsed(); 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)
} }
fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
@@ -71,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(); 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") { 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; continue;
} }
let output_path = out_dir.join(relative).with_extension("rs"); 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 // create parent directories
if let Some(parent) = output_path.parent() { if let Some(parent) = output_path.parent() {
if let Err(e) = fs::create_dir_all(parent) { if let Err(e) = fs::create_dir_all(parent) {
@@ -147,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<PathBuf> { pub fn find_project_root() -> Option<PathBuf> {
let mut dir = std::env::current_dir().ok()?; let mut dir = std::env::current_dir().ok()?;