Merge pull request #35 from mist-go/errors-and-caching
Errors and caching
This commit is contained in:
Generated
+64
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}),
|
||||||
|
})?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 }
|
||||||
@@ -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
@@ -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())
|
||||||
|
}
|
||||||
+39
-13
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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
@@ -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");
|
||||||
|
|||||||
@@ -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()?;
|
||||||
|
|
||||||
Reference in New Issue
Block a user