Merge pull request #78 from mist-go/rewrite-map-system

Rewrite map system
This commit is contained in:
2026-06-15 15:34:59 +02:00
committed by GitHub
12 changed files with 217 additions and 160 deletions
Generated
+7
View File
@@ -45,6 +45,12 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bytecount"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
[[package]]
name = "bytes"
version = "1.11.1"
@@ -493,6 +499,7 @@ dependencies = [
name = "mist-codegen"
version = "0.3.3-alpha.0"
dependencies = [
"bytecount",
"mist-parser",
]
+35 -35
View File
@@ -6,7 +6,7 @@ use std::{
};
use cargo_metadata::{CompilerMessage, Message};
use mist_parser::rev_mapper::{RustMap, find_mapping, get_mapping};
use mist_parser::rev_mapper;
#[derive(Debug, Clone)]
pub struct MistDiagnosticMessage {
@@ -39,7 +39,7 @@ pub fn build(mut args: Vec<String>, root: PathBuf) -> Vec<MistDiagnostic> {
let mut diagnostics = Vec::new();
let mut mapping = HashMap::new();
let mut mapping: HashMap<rev_mapper::RustMap, rev_mapper::MistMap> = HashMap::new();
let mist_src = format!(".mist{MAIN_SEPARATOR}lsp");
@@ -64,44 +64,44 @@ pub fn build(mut args: Vec<String>, root: PathBuf) -> Vec<MistDiagnostic> {
break;
}
let map = mapping.entry(rust_path.clone()).or_insert_with(|| {
get_mapping(
&fs::read_to_string(rust_path)
.expect("Failed to read file for mapping"),
)
});
// let map = mapping.entry(rust_path.clone()).or_insert_with(|| {
// get_mapping(
// &fs::read_to_string(rust_path)
// .expect("Failed to read file for mapping"),
// )
// });
let mist_span =
find_mapping(&map, &RustMap(span.line_end, span.column_start))
.expect("Unable to find mapping");
// let mist_span =
// find_mapping(&map, &RustMap(span.line_end, span.column_start))
// .expect("Unable to find mapping");
let mist_msg = MistDiagnosticMessage {
message: format!(
"{}: {}",
msg.message.message,
span.label.clone().unwrap_or_default()
),
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,
};
// let mist_msg = MistDiagnosticMessage {
// message: format!(
// "{}: {}",
// msg.message.message,
// span.label.clone().unwrap_or_default()
// ),
// 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))
}
// 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))
}
// cargo_metadata::diagnostic::DiagnosticLevel::Warning => {
// diagnostics.push(MistDiagnostic::Warning(mist_msg))
// }
_ => {}
}
// _ => {}
// }
}
}
}
+35 -34
View File
@@ -57,29 +57,30 @@ impl Backend {
match self.mapping.lock().await.get(&rs_path) {
Some(mapping) => {
rs_loc
// FIX: Match the find_mapping operation instead of calling .expect("Failed to map")
match rev_mapper::find_mapping(
mapping,
&rev_mapper::RustMap(
rs_loc.range.start.line as usize,
rs_loc.range.start.character as usize,
),
) {
Some((_, rev_mapper::MistMap(line, character))) => Location {
uri: Url::from_file_path(from_rust_to_mist(rs_path)).unwrap(),
range: Range {
start: Position {
line: line as u32 - 1,
character: character as u32,
},
end: Position {
line: line as u32 - 1,
character: character as u32 + 1,
},
},
},
None => rs_loc,
}
// match rev_mapper::find_mapping(
// mapping,
// &rev_mapper::RustMap(
// rs_loc.range.start.line as usize,
// rs_loc.range.start.character as usize,
// ),
// ) {
// Some((_, rev_mapper::MistMap(line, character))) => Location {
// uri: Url::from_file_path(from_rust_to_mist(rs_path)).unwrap(),
// range: Range {
// start: Position {
// line: line as u32 - 1,
// character: character as u32,
// },
// end: Position {
// line: line as u32 - 1,
// character: character as u32 + 1,
// },
// },
// },
// None => rs_loc,
// }
}
None => rs_loc,
}
@@ -167,10 +168,10 @@ impl LanguageServer for Backend {
.insert(file.clone(), Rope::from_str(&text));
// store mapping
mapping
.lock()
.await
.insert(rust_path, rev_mapper::get_mapping(&transpiled));
// mapping
// .lock()
// .await
// .insert(rust_path, rev_mapper::get_mapping(&transpiled));
}
}
}
@@ -311,10 +312,10 @@ impl LanguageServer for Backend {
params.text_document.uri = Url::from_file_path(&rust_path).unwrap();
self.mapping.lock().await.insert(
rust_path,
rev_mapper::get_mapping(&params.text_document.text),
);
// self.mapping.lock().await.insert(
// rust_path,
// rev_mapper::get_mapping(&params.text_document.text),
// );
}
Err(e) => {
self.client
@@ -353,10 +354,10 @@ impl LanguageServer for Backend {
Ok(transpiled_text) => {
change.text = transpiled_text;
self.mapping
.lock()
.await
.insert(rust_path, rev_mapper::get_mapping(&change.text));
// self.mapping
// .lock()
// .await
// .insert(rust_path, rev_mapper::get_mapping(&change.text));
}
Err(e) => {
self.client
+10 -7
View File
@@ -135,19 +135,22 @@ pub fn transpile_file(path: &Path, output_path: &Path) -> Result<(), String> {
// If parsing fails, return the error string back gracefully so the LSP can show it
let ast = parser_result.map_err(|e| format!("parse failed in {}:\n{}", path.display(), e))?;
let mut gc = mist_codegen::RustCodegen::new();
let output = gc.generate(ast);
panic!();
fs::write(output_path, output)
.map_err(|e| format!("failed to write output {}: {}", output_path.display(), e))?;
// let mut gc = mist_codegen::RustCodegen::new();
// let output = gc.generate(ast);
Ok(())
// fs::write(output_path, output)
// .map_err(|e| format!("failed to write output {}: {}", output_path.display(), e))?;
// Ok(())
}
pub fn transpile_text<'a>(source: &'a str) -> Result<String, ParseError<'a, Vec<TopLevel>>> {
let mut gc = mist_codegen::RustCodegen::new();
panic!();
// let mut gc = mist_codegen::RustCodegen::new();
Ok(gc.generate(mist_parser::parse(&source)?))
// Ok(gc.generate(mist_parser::parse(&source)?))
}
fn should_skip(source: &Path, output: &Path) -> bool {
+1
View File
@@ -9,4 +9,5 @@ keywords = ["compiler", "language", "mist"]
categories = ["compilers"]
[dependencies]
bytecount = "0.6.9"
mist-parser = { workspace = true }
+1 -1
View File
@@ -522,7 +522,7 @@ fn construct_pattern(pat: &Pattern, idx: usize) -> Pattern {
}
pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustCodegen) {
cg.add(&format!(
cg.add_indented(&format!(
"{}fn {}{}(",
method.visibility.get_rust(),
method.name.get_rust(),
+29 -13
View File
@@ -3,7 +3,12 @@ pub mod expr;
pub mod statement;
pub mod top_level;
use mist_parser::ast::*;
use std::path::PathBuf;
use mist_parser::{
ast::*,
rev_mapper::{Mapping, MistMap, RustMap},
};
pub struct Context {
pub expr_ensure_semicolon: bool,
@@ -22,17 +27,20 @@ pub trait GetRust {
}
}
#[derive(Default)]
pub struct RustCodegen {
output: String,
indent: usize,
pub mapping: Mapping,
position: RustMap,
}
impl RustCodegen {
pub fn new() -> Self {
pub fn new(mist_path: PathBuf) -> Self {
Self {
output: String::new(),
indent: 0,
mapping: Mapping::new(mist_path),
position: RustMap(1, 0),
}
}
@@ -41,6 +49,17 @@ impl RustCodegen {
}
fn add(&mut self, s: &str) {
let newline_count = bytecount::count(s.as_bytes(), b'\n');
if newline_count == 0 {
self.position.1 += s.len();
} else {
self.position.0 += newline_count;
let last_newline = s.rfind('\n').unwrap();
self.position.1 = s.len() - last_newline - 1;
}
self.output.push_str(s);
}
@@ -123,21 +142,18 @@ impl GenRust for Attribute {
}
}
impl<T: GetRust> GetRust for Spanned<T> {
fn get_rust(&self) -> String {
format!(
"/* {}:{} */ {}",
self.line,
self.column,
self.item.get_rust()
)
impl<T: GetRust> GenRust for T {
fn gen_rust(&self, _: &mut Context, cg: &mut RustCodegen) {
cg.add(&self.get_rust());
}
}
impl<T: GenRust> GenRust for Spanned<T> {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
cg.add_indentedln(&format!("/* {}:{} */", self.line, self.column));
cg.add_indented("");
cg.mapping
.map
.insert((cg.position, MistMap(self.line, self.column)));
self.item.gen_rust(ctx, cg);
}
}
+2
View File
@@ -11,12 +11,14 @@ impl GenRust for Block {
for stmt in &self.statements {
ctx.expr_ensure_semicolon = true;
cg.add_indented("");
stmt.gen_rust(ctx, cg);
cg.addln("");
}
if let Some(soft_return) = &self.soft_return {
ctx.expr_ensure_semicolon = false;
cg.add_indented("");
soft_return.gen_rust(ctx, cg);
cg.addln("");
}
+9 -4
View File
@@ -73,7 +73,7 @@ impl GenRust for ImplDecl {
impl GenRust for FunctionDecl {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
cg.add(&format!(
cg.add_indented(&format!(
"{}fn {}{}(",
self.visibility.get_rust(),
self.name.get_rust(),
@@ -97,8 +97,9 @@ impl GenRust for FunctionDecl {
if let Some(body) = &self.body {
cg.add(" ");
body.gen_rust(ctx, cg);
cg.addln("");
} else {
cg.add(";");
cg.addln(";");
}
}
}
@@ -195,7 +196,9 @@ impl GenRust for TopLevelKind {
cg.indent += 1;
for field in fields {
cg.add_indentedln(&field.get_rust());
cg.add_indented("");
field.gen_rust(ctx, cg);
cg.addln("");
}
cg.indent -= 1;
@@ -216,7 +219,9 @@ impl GenRust for TopLevelKind {
cg.indent += 1;
for field in fields {
cg.add_indentedln(&(field.get_rust() + ","));
cg.add_indented("");
field.gen_rust(ctx, cg);
cg.addln(",");
}
cg.indent -= 1;
+13 -26
View File
@@ -1,9 +1,7 @@
pub module builder;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::MAIN_SEPARATOR;
use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
@@ -31,8 +29,6 @@ pub fn build(mut args Vec<String>, root PathBuf) bool {
args.remove(0);
args.insert(1, "--message-format=json".to_string());
let is_root = root == env::current_dir().expect("Failed getting env");
let mut command = Command::new("cargo")
.args(args)
.stdout(Stdio::piped())
@@ -47,8 +43,6 @@ pub fn build(mut args Vec<String>, root PathBuf) bool {
let mut mapping = HashMap::new();
let mist_src = format!(".mist{MAIN_SEPARATOR}src");
for message in cargo_metadata::Message::parse_stream(&mut reader) {
match message {
Ok[Message::CompilerMessage[msg]] => {
@@ -56,29 +50,23 @@ pub fn build(mut args Vec<String>, root PathBuf) bool {
if span.is_primary {
let rust_path = root.join(&span.file_name);
let mist_file = span
.file_name
.replacen(&mist_src, "src", 1)
.trim_end_matches(".rs")
.to_string()
+ ".mist";
let mapping_path = rust_path.with_extension("map.json");
let mist_path = root.join(&mist_file);
if !fs::exists(&mist_path).expect("Unable to check if mist file exists") {
if !fs::exists(&mapping_path).expect("Unable to check if map file exists") {
diagnostics.push(MistDiagnostic::Rust(msg));
break;
}
let map = mapping.entry(rust_path.clone()).or_insert_with(fn() {
rev_mapper::get_mapping(
&fs::read_to_string(rust_path)
.expect("Failed to read file for mapping")
)
let map = mapping.entry(mapping_path.clone()).or_insert_with(fn() {
let map_str = fs::read_to_string(mapping_path).expect("Failed to read map file");
serde_json::from_str<rev_mapper::Mapping>(&map_str).expect("Failed to parse map file")
});
let mist_file = map.mist_path.strip_prefix(&root);
let [_, rev_mapper::MistMap[line, column]] =
rev_mapper::find_mapping(&map, &rev_mapper::RustMap(span.line_end, span.column_start))
map.find(&rev_mapper::RustMap(span.line_end, span.column_start))
.expect("Unable to find mapping");
let mist_msg = MistDiagnosticMessage {
@@ -87,13 +75,12 @@ pub fn build(mut args Vec<String>, root PathBuf) bool {
msg.message.message,
span.label.clone().unwrap_or_default()
),
file_name: if is_root {
(); // TODO: fix this
mist_file
file_name: if let Ok(mist_file) = mist_file {
mist_file.to_string_lossy().to_string()
} else {
mist_path.to_string_lossy().to_string()
map.mist_path.to_string_lossy().to_string()
},
file_path: mist_path,
file_path: map.mist_path.clone(),
line: line,
column: column
};
+18 -2
View File
@@ -200,7 +200,7 @@ fn transpile_file(path *PathBuf, source *str, mut output_file PathBuf, mod_decl
}
}
let mut gc = mist_codegen::RustCodegen::new();
let mut gc = mist_codegen::RustCodegen::new(path.clone());
let parsed = match mist_parser::parse(source) {
Ok[ast] => ast;
@@ -238,13 +238,29 @@ fn transpile_file(path *PathBuf, source *str, mut output_file PathBuf, mod_decl
let res = fs::write(&output_file, format!("{mod_decl}{output}"));
gc.mapping.shift_rust(mod_decl.lines().count() as isize, 0);
let output_file_map = output_file.with_extension("map.json");
let res_map = fs::write(&output_file_map, serde_json::to_string(&gc.mapping).unwrap());
if res_map.is_err() {
eprintln!(
"error: failed to write mapping output {}\n {}",
output_file_map.display(),
res.as_ref().unwrap_err(),
);
}
if res.is_err() {
eprintln!(
"error: failed to write output {}\n {}",
output_file.display(),
res.unwrap_err(),
res.as_ref().unwrap_err(),
);
}
if res_map.is_err() || res.is_err() {
process::exit(1);
}
}
+57 -38
View File
@@ -1,51 +1,70 @@
use std::collections::HashSet;
use std::{collections::HashSet, path::PathBuf};
use pest::Parser;
use pest_derive::Parser;
use serde::{Deserialize, Serialize};
#[derive(Parser)]
#[grammar = "./src/rev_mapper/grammar.pest"]
pub struct MistMapperParser;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[derive(
Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
)]
pub struct MistMap(pub usize, pub usize);
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[derive(
Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
)]
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(line, col)));
}
}
mapping
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Mapping {
pub mist_path: PathBuf,
pub map: HashSet<(RustMap, MistMap)>,
}
pub fn find_mapping(
mapping: &HashSet<(RustMap, MistMap)>,
target: &RustMap,
) -> Option<(RustMap, MistMap)> {
mapping
impl Mapping {
pub fn new(mist_path: PathBuf) -> Self {
Self {
mist_path,
map: HashSet::new(),
}
}
pub fn find(&self, target: &RustMap) -> Option<(RustMap, MistMap)> {
self.map
.iter()
.copied()
.filter(|(rust, _)| rust <= target)
.max_by_key(|(rust, _)| *rust)
}
pub fn shift_rust(&mut self, lines: isize, cols: isize) {
self.map = self
.map
.iter()
.map(|(rust, mist)| (rust.shifted(lines, cols), *mist))
.collect();
}
pub fn shift_mist(&mut self, lines: isize, cols: isize) {
self.map = self
.map
.iter()
.map(|(rust, mist)| (*rust, mist.shifted(lines, cols)))
.collect();
}
}
impl RustMap {
pub fn shifted(self, lines: isize, cols: isize) -> Self {
Self(
self.0.saturating_add_signed(lines),
self.1.saturating_add_signed(cols),
)
}
}
impl MistMap {
pub fn shifted(self, lines: isize, cols: isize) -> Self {
Self(
self.0.saturating_add_signed(lines),
self.1.saturating_add_signed(cols),
)
}
}