Merge pull request #105 from mist-go/cli-improvements
CLI improvements, module system fixes, project scaffolding, and bug fixes
This commit is contained in:
Generated
+1
@@ -519,6 +519,7 @@ version = "0.3.7-alpha.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"mist-analyzer",
|
"mist-analyzer",
|
||||||
"mist-api",
|
"mist-api",
|
||||||
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ include = [
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
mist-analyzer = { workspace = true }
|
mist-analyzer = { workspace = true }
|
||||||
mist-api = { workspace = true }
|
mist-api = { workspace = true }
|
||||||
|
toml = "1.1.2"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ pub bool build(Vec<String> mut args, PathBuf root)
|
|||||||
serde_json::from_str<rev_mapper::Mapping>(&map_str).expect("Failed to parse 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 mist_file = map.mist_path.strip_prefix(&root);
|
||||||
let (_, rev_mapper::MistMap(line, column)) = map.find(&rev_mapper::RustMap(span.line_end, span.column_start)).expect("Unable to find mapping");
|
let (_, rev_mapper::MistMap(line, column)) = map.find(&rev_mapper::RustMap(span.line_end, span.column_start)).unwrap_or_default();
|
||||||
let mist_msg = MistDiagnosticMessage {
|
let mist_msg = MistDiagnosticMessage {
|
||||||
message: format!("{}: {}",
|
message: format!("{}: {}",
|
||||||
msg.message.message,
|
msg.message.message,
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ pub class Module
|
|||||||
|
|
||||||
pub PathBuf output_path(&self, PathBuf& parent_dir, Option<(mist_parser::ast::Visibility, mist_parser::ast::Identifier)>& curr_mod_decl)
|
pub PathBuf output_path(&self, PathBuf& parent_dir, Option<(mist_parser::ast::Visibility, mist_parser::ast::Identifier)>& curr_mod_decl)
|
||||||
{
|
{
|
||||||
let name = if let Some((_, name)) = curr_mod_decl {
|
let name = if self.path.is_dir() || self.is_package() {
|
||||||
|
&self.name
|
||||||
|
} else if let Some((_, name)) = curr_mod_decl {
|
||||||
&name.0
|
&name.0
|
||||||
} else {
|
} else {
|
||||||
&self.name
|
&self.name
|
||||||
|
|||||||
@@ -136,12 +136,37 @@ impl modules::Module
|
|||||||
}
|
}
|
||||||
(bool, String) write_transpile(&self, String output, PathBuf& parent_dir, bool child_changed)
|
(bool, String) write_transpile(&self, String output, PathBuf& parent_dir, bool child_changed)
|
||||||
{
|
{
|
||||||
if self.path.is_dir() {
|
if self.path.is_dir() || self.is_package() {
|
||||||
let output_file = self.output_path(parent_dir, &None);
|
let output_file = self.output_path(parent_dir, &None);
|
||||||
if output.len() == 0 {
|
let final_output = if self.is_package() {
|
||||||
return (true, String::new());
|
let source = match fs::read_to_string(&self.path) {
|
||||||
}
|
Ok(s) => s,
|
||||||
let res = fs::write(&output_file, output);
|
Err(e) => {
|
||||||
|
eprintln!("error: failed to read file {}\n {}", self.path.display(), e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let curr_mod_decl = mist_parser::parse_module(&source).expect("Failed parsing module");
|
||||||
|
let (result_path, gc, rust_code) = match transpile_code(&self.path, &source, output_file.clone(), &output, &curr_mod_decl) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
decode_err(&e, &self.path);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let map_path = result_path.with_extension("map.json");
|
||||||
|
if let Some(parent) = map_path.parent() {
|
||||||
|
let _ = fs::create_dir_all(parent);
|
||||||
|
}
|
||||||
|
fs::write(&map_path, serde_json::to_string(&gc.mapping).unwrap()).expect("Failed to write map file");
|
||||||
|
rust_code
|
||||||
|
} else {
|
||||||
|
if output.len() == 0 {
|
||||||
|
return (true, String::new());
|
||||||
|
}
|
||||||
|
output
|
||||||
|
};
|
||||||
|
let res = fs::write(&output_file, final_output);
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
eprintln!("error: failed to write output {}\n {}",
|
eprintln!("error: failed to write output {}\n {}",
|
||||||
output_file.display(),
|
output_file.display(),
|
||||||
@@ -222,13 +247,16 @@ pub void transpile_file(PathBuf& path, str& source, PathBuf output_file, str& mo
|
|||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if let Some(parent) = output_file.parent() {
|
||||||
|
let _ = fs::create_dir_all(parent);
|
||||||
|
}
|
||||||
let res = fs::write(&output_file, output);
|
let res = fs::write(&output_file, output);
|
||||||
let output_file_map = output_file.with_extension("map.json");
|
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());
|
let res_map = fs::write(&output_file_map, serde_json::to_string(&gc.mapping).unwrap());
|
||||||
if res_map.is_err() {
|
if res_map.is_err() {
|
||||||
eprintln!("error: failed to write mapping output {}\n {}",
|
eprintln!("error: failed to write mapping output {}\n {}",
|
||||||
output_file_map.display(),
|
output_file_map.display(),
|
||||||
res.as_ref().unwrap_err(),);
|
res_map.as_ref().unwrap_err(),);
|
||||||
}
|
}
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
eprintln!("error: failed to write output {}\n {}",
|
eprintln!("error: failed to write output {}\n {}",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module decl_test;
|
pub module decl_test;
|
||||||
|
pub module decl_test;
|
||||||
|
|
||||||
pub void test_let_basic()
|
pub void test_let_basic()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module expr_test;
|
pub module expr_test;
|
||||||
|
pub module expr_test;
|
||||||
|
|
||||||
pub void test_literals()
|
pub void test_literals()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub module package;
|
||||||
pub module common;
|
pub module common;
|
||||||
|
|
||||||
pub void test_package() {}
|
pub void test_package() {}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module statement_test;
|
pub module statement_test;
|
||||||
|
pub module statement_test;
|
||||||
|
|
||||||
pub void test_var_decl()
|
pub void test_var_decl()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module types_test;
|
pub module types_test;
|
||||||
|
pub module types_test;
|
||||||
|
|
||||||
pub void test_integer_type() {
|
pub void test_integer_type() {
|
||||||
i32 x = 42;
|
i32 x = 42;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module attribute_test;
|
pub module attribute_test;
|
||||||
|
pub module attribute_test;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Debuggable
|
pub struct Debuggable
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module class_test;
|
pub module class_test;
|
||||||
|
pub module class_test;
|
||||||
|
|
||||||
pub class Animal
|
pub class Animal
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module enum_test;
|
pub module enum_test;
|
||||||
|
pub module enum_test;
|
||||||
|
|
||||||
enum OptionInt
|
enum OptionInt
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module function_test;
|
pub module function_test;
|
||||||
|
pub module function_test;
|
||||||
|
|
||||||
void greet()
|
void greet()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module impl_test;
|
pub module impl_test;
|
||||||
|
pub module impl_test;
|
||||||
|
|
||||||
struct Vector2
|
struct Vector2
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module struct_test;
|
pub module struct_test;
|
||||||
|
pub module struct_test;
|
||||||
|
|
||||||
struct Point
|
struct Point
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub module trait_test;
|
pub module trait_test;
|
||||||
|
pub module trait_test;
|
||||||
|
|
||||||
trait Speak
|
trait Speak
|
||||||
{
|
{
|
||||||
|
|||||||
+109
-21
@@ -10,14 +10,15 @@ use mist_api::transpiler;
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
Vec<String> args = env::args().collect();
|
Vec<String> mut args = env::args().collect();
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
print_usage();
|
print_usage();
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
match args[1].as_str() {
|
match args[1].as_str() {
|
||||||
"run" | "build" | "check" | "r" | "b" | "c" => {
|
"run" | "build" | "check" | "test" | "publish" | "bench" | "doc" | "fix" | "clippy" | "r" | "b" | "c" => {
|
||||||
let root = env::current_dir().expect("Unable to find project root");
|
let mut root = env::current_dir().expect("Unable to find project root");
|
||||||
|
modify_args(&mut args, &mut root);
|
||||||
transpiler::transpile(&root);
|
transpiler::transpile(&root);
|
||||||
println!("");
|
println!("");
|
||||||
if builder::build(args, root) {
|
if builder::build(args, root) {
|
||||||
@@ -27,12 +28,20 @@ void main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"transpile" | "t" => {
|
"transpile" | "t" => {
|
||||||
let root = env::current_dir().expect("Unable to find project root");
|
let mut root = env::current_dir().expect("Unable to find project root");
|
||||||
|
modify_args(&mut args, &mut root);
|
||||||
transpiler::transpile(&root);
|
transpiler::transpile(&root);
|
||||||
}
|
}
|
||||||
|
"clean" => {
|
||||||
|
args.remove(0);
|
||||||
|
process::Command::new("cargo").args(args).stdout(process::Stdio::inherit()).stderr(process::Stdio::inherit()).stdin(process::Stdio::inherit()).spawn().expect("Failed to run cargo").wait().expect("Unable to wait");
|
||||||
|
}
|
||||||
"init" => {
|
"init" => {
|
||||||
init_project(args);
|
init_project(args);
|
||||||
}
|
}
|
||||||
|
"new" => {
|
||||||
|
new_project(args);
|
||||||
|
}
|
||||||
"version" | "--version" | "-v" => {
|
"version" | "--version" | "-v" => {
|
||||||
println!("mist {}", env!("CARGO_PKG_VERSION"));
|
println!("mist {}", env!("CARGO_PKG_VERSION"));
|
||||||
}
|
}
|
||||||
@@ -47,44 +56,123 @@ void main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void modify_args(Vec<String> mut& args, std::path::PathBuf mut& root)
|
||||||
|
{
|
||||||
|
if let Some(path_arg) = args.get(2) {
|
||||||
|
if path_arg == "--path" {
|
||||||
|
if args.len() > 3 {
|
||||||
|
let path_arg = args[3].clone();
|
||||||
|
*root = root.join(&path_arg);
|
||||||
|
args.remove(2);
|
||||||
|
args.remove(2);
|
||||||
|
args.push(format!("--manifest-path={}/Cargo.toml", root.display()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void print_usage()
|
void print_usage()
|
||||||
{
|
{
|
||||||
println!("Mist - the mist compiler\n");
|
println!("Mist - the mist compiler\n");
|
||||||
println!(" View our documentation! \x1b[35mhttps://mist.selimaj.dev\x1b[0m");
|
println!(" View our documentation! \x1b[95mhttps://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[95mhttps://github.com/mist-go\x1b[0m\n");
|
||||||
println!("usage:");
|
println!("usage:");
|
||||||
println!(" \x1b[36m mist run\x1b[0m,\x1b[36m r\x1b[0m run the project in the current directory\n");
|
println!(" \x1b[96m mist run\x1b[0m,\x1b[96m r\x1b[0m run the project\n");
|
||||||
println!(" \x1b[36m mist build\x1b[0m,\x1b[36m b\x1b[0m build the project in the current directory\n");
|
println!(" \x1b[96m mist build\x1b[0m,\x1b[96m b\x1b[0m build the project\n");
|
||||||
println!(" \x1b[36m mist transpile\x1b[0m,\x1b[36m t\x1b[0m transpile the project in the current directory\n");
|
println!(" \x1b[96m mist test\x1b[0m test the project\n");
|
||||||
println!(" \x1b[36m mist check\x1b[0m,\x1b[36m c\x1b[0m check the project in the current directory\n");
|
println!(" \x1b[96m mist publish\x1b[0m publish the project\n");
|
||||||
println!(" \x1b[36m mist init\x1b[0m initialize a project in the current folder\n");
|
println!(" \x1b[96m mist bench\x1b[0m benchmark the project\n");
|
||||||
println!(" \x1b[36m mist version \x1b[0m print the compiler version\n");
|
println!(" \x1b[96m mist doc\x1b[0m build documentation\n");
|
||||||
println!(" \x1b[36m mist help\x1b[0m print this message\n");
|
println!(" \x1b[96m mist fix\x1b[0m automatically fix warnings\n");
|
||||||
|
println!(" \x1b[96m mist clippy\x1b[0m lint the project\n");
|
||||||
|
println!(" \x1b[96m mist check\x1b[0m,\x1b[96m c\x1b[0m check the project\n");
|
||||||
|
println!(" \x1b[96m mist clean\x1b[0m clean build artifacts\n");
|
||||||
|
println!(" \x1b[96m mist transpile\x1b[0m,\x1b[96m t\x1b[0m transpile the project\n");
|
||||||
|
println!(" \x1b[96m mist init\x1b[0m initialize a project in the current folder\n");
|
||||||
|
println!(" \x1b[96m mist new\x1b[0m create a new project\n");
|
||||||
|
println!(" \x1b[96m mist version \x1b[0m print the compiler version\n");
|
||||||
|
println!(" \x1b[96m mist help\x1b[0m print this message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_project(Vec<String> mut args)
|
void init_project(Vec<String> mut args)
|
||||||
{
|
{
|
||||||
args.remove(0);
|
args.remove(0);
|
||||||
process::Command::new("cargo").args(args).stdout(process::Stdio::inherit()).stderr(process::Stdio::inherit()).stdin(process::Stdio::inherit()).spawn().expect("Failed to run cargo").wait().expect("Unable to wait");
|
let status = process::Command::new("cargo").args(args).stdout(process::Stdio::inherit()).stderr(process::Stdio::inherit()).stdin(process::Stdio::inherit()).spawn().expect("Failed to run cargo").wait().expect("Unable to wait");
|
||||||
|
if !status.success() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool is_lib = fs::metadata("src/lib.rs").is_ok();
|
bool is_lib = fs::metadata("src/lib.rs").is_ok();
|
||||||
if is_lib {
|
if is_lib {
|
||||||
fs::remove_file("src/lib.rs").expect("Failed to remove src/lib.rs");
|
fs::remove_file("src/lib.rs").expect("Failed to remove src/lib.rs");
|
||||||
fs::write("src/lib.mist", "fn test() {\n}").expect("Failed to create src/lib.mist");
|
fs::write("src/lib.mist", "void test() {\n}").expect("Failed to create src/lib.mist");
|
||||||
} else {
|
} else {
|
||||||
fs::remove_file("src/main.rs").expect("Failed to remove src/main.rs");
|
fs::remove_file("src/main.rs").expect("Failed to remove src/main.rs");
|
||||||
fs::write("src/main.mist", "fn main() {\n println!(\"Hello, World!\");\n}\n").expect("Failed to create src/main.mist");
|
fs::write("src/main.mist", "void main() {\n println!(\"Hello, World!\");\n}\n").expect("Failed to create src/main.mist");
|
||||||
}
|
}
|
||||||
inject_mist_target(is_lib);
|
inject_mist_target(is_lib);
|
||||||
println!("\n\x1b[34minfo\x1b[0m: Please open Cargo.toml and adjust `\x1b[35mname\x1b[0m = ` as needed, Thank you for using Mist!\n");
|
add_mist_toml(is_lib);
|
||||||
|
add_gitignore();
|
||||||
|
println!("Thank you for using Mist!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_project(Vec<String> mut args)
|
||||||
|
{
|
||||||
|
args.remove(0);
|
||||||
|
if args.len() < 2 {
|
||||||
|
eprintln!("error: missing project name\n");
|
||||||
|
print_usage();
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
String project_name = args[1].clone();
|
||||||
|
let status = process::Command::new("cargo").args(args).stdout(process::Stdio::inherit()).stderr(process::Stdio::inherit()).stdin(process::Stdio::inherit()).spawn().expect("Failed to run cargo").wait().expect("Unable to wait");
|
||||||
|
if !status.success() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::path::PathBuf project_path = env::current_dir().expect("Unable to find project root").join(&project_name);
|
||||||
|
env::set_current_dir(&project_path).expect("Failed to change to project directory");
|
||||||
|
bool is_lib = fs::metadata("src/lib.rs").is_ok();
|
||||||
|
if is_lib {
|
||||||
|
fs::remove_file("src/lib.rs").expect("Failed to remove src/lib.rs");
|
||||||
|
fs::write("src/lib.mist", "void test() {\n}").expect("Failed to create src/lib.mist");
|
||||||
|
} else {
|
||||||
|
fs::remove_file("src/main.rs").expect("Failed to remove src/main.rs");
|
||||||
|
fs::write("src/main.mist", "void main() {\n println!(\"Hello, World!\");\n}\n").expect("Failed to create src/main.mist");
|
||||||
|
}
|
||||||
|
inject_mist_target(is_lib);
|
||||||
|
add_mist_toml(is_lib);
|
||||||
|
add_gitignore();
|
||||||
|
println!("Thank you for using Mist!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void inject_mist_target(bool is_lib)
|
void inject_mist_target(bool is_lib)
|
||||||
{
|
{
|
||||||
String toml_content = fs::read_to_string("Cargo.toml").expect("Failed to read Cargo.toml");
|
String toml_content = fs::read_to_string("Cargo.toml").expect("Failed to read Cargo.toml");
|
||||||
str& inject = if is_lib {
|
toml::Value parsed = toml::from_str(&toml_content).expect("Failed to parse Cargo.toml");
|
||||||
"\n[lib]\nname = \"my_lib\"\npath = \".mist/src/lib.rs\"\n"
|
String name = parsed["package"]["name"].as_str().expect("Missing package.name in Cargo.toml").to_string();
|
||||||
|
String inject = if is_lib {
|
||||||
|
format!("\n[lib]\nname = \"{name}\"\npath = \".mist/src/lib.rs\"\n")
|
||||||
} else {
|
} else {
|
||||||
"\n[[bin]]\nname = \"my_bin\"\npath = \".mist/src/main.rs\"\n"
|
format!("\n[[bin]]\nname = \"{name}\"\npath = \".mist/src/main.rs\"\n")
|
||||||
};
|
};
|
||||||
fs::write("Cargo.toml", toml_content + inject).expect("Failed to inject to Cargo.toml");
|
fs::write("Cargo.toml", toml_content + &inject).expect("Failed to inject to Cargo.toml");
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_mist_toml(bool is_lib)
|
||||||
|
{
|
||||||
|
str& content = if is_lib {
|
||||||
|
"package = \"lib.mist\"\npackages = []\ninclude = []\n"
|
||||||
|
} else {
|
||||||
|
"package = \"main.mist\"\npackages = []\ninclude = []\n"
|
||||||
|
};
|
||||||
|
fs::write("Mist.toml", content).expect("Failed to add Mist.toml");
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_gitignore()
|
||||||
|
{
|
||||||
|
if fs::metadata(".gitignore").is_ok() {
|
||||||
|
String content = fs::read_to_string(".gitignore").expect("Failed to read .gitignore");
|
||||||
|
if !content.contains(".mist") {
|
||||||
|
fs::write(".gitignore", content + "\n.mist\n").expect("Failed to write .gitignore");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user