Use structs instead of enum structs, add first implementations of other subcommands
This commit is contained in:
parent
d7a3f19967
commit
54e536d11f
|
@ -5,9 +5,16 @@ edition = "2021"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
zip = ["shulkerbox/zip"]
|
||||
lang-debug = []
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.4", features = ["derive"] }
|
||||
colored = "2.1.0"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
thiserror = "1.0.58"
|
||||
toml = "0.8.12"
|
||||
shulkerscript-lang = {path = "../shulkerscript-lang"}
|
||||
shulkerbox = {path = "../shulkerbox", default-features = false}
|
||||
|
||||
|
|
55
src/cli.rs
55
src/cli.rs
|
@ -1,6 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use crate::{error::Result, subcommands};
|
||||
use crate::{
|
||||
error::Result,
|
||||
subcommands::{self, CompileArgs, InitArgs},
|
||||
};
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -15,43 +16,27 @@ pub struct Args {
|
|||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum Command {
|
||||
/// Initialize a new project in the current directory.
|
||||
Init {
|
||||
/// The path of the folder to initialize in.
|
||||
#[clap(default_value = ".")]
|
||||
path: PathBuf,
|
||||
/// The name of the project.
|
||||
#[clap(short, long)]
|
||||
name: Option<String>,
|
||||
/// The description of the project.
|
||||
#[clap(short, long)]
|
||||
description: Option<String>,
|
||||
/// The pack format version.
|
||||
#[clap(short, long)]
|
||||
pack_format: Option<u8>,
|
||||
/// Force initialization even if the directory is not empty.
|
||||
#[clap(short, long)]
|
||||
force: bool,
|
||||
},
|
||||
/// Initialize a new project.
|
||||
Init(InitArgs),
|
||||
/// Compile the project.
|
||||
Compile(CompileArgs),
|
||||
#[cfg(feature = "zip")]
|
||||
/// Compile and package the project.
|
||||
Package(subcommands::PackageArgs),
|
||||
#[cfg(feature = "lang-debug")]
|
||||
/// Compile the project and dump the intermediate state.
|
||||
LangDebug(subcommands::LangDebugArgs),
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
match &self.cmd {
|
||||
Command::Init {
|
||||
path,
|
||||
name,
|
||||
description,
|
||||
pack_format,
|
||||
force,
|
||||
} => subcommands::init(
|
||||
self.verbose,
|
||||
path,
|
||||
name.as_deref(),
|
||||
description.as_deref(),
|
||||
*pack_format,
|
||||
*force,
|
||||
)?,
|
||||
Command::Init(args) => subcommands::init(self.verbose, args)?,
|
||||
Command::Compile(args) => subcommands::compile(self.verbose, args)?,
|
||||
#[cfg(feature = "zip")]
|
||||
Command::Package(args) => subcommands::package(self.verbose, args)?,
|
||||
#[cfg(feature = "lang-debug")]
|
||||
Command::LangDebug(args) => subcommands::lang_debug(args)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -14,6 +14,10 @@ pub enum Error {
|
|||
NonEmptyDirectoryError(PathBuf),
|
||||
#[error("An error occured because the path {0} is not a directory.")]
|
||||
NotDirectoryError(PathBuf),
|
||||
#[error("An error occured because the path is neither a pack directory or a pack.toml file.")]
|
||||
InvalidPackPathError(PathBuf),
|
||||
#[error("An error occured while compiling the project.")]
|
||||
ShulkerScriptError(#[from] shulkerscript_lang::base::Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
use crate::{
|
||||
config::ProjectConfig,
|
||||
error::{Error, Result},
|
||||
terminal_output::{print_error, print_info},
|
||||
};
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use crate::util;
|
||||
|
||||
#[derive(Debug, clap::Args, Clone)]
|
||||
pub struct CompileArgs {
|
||||
/// The path of the project to compile.
|
||||
#[clap(default_value = ".")]
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
pub fn compile(_verbose: bool, args: &CompileArgs) -> Result<()> {
|
||||
let path = args.path.as_path();
|
||||
|
||||
let str_path = util::to_absolute_path(path)?;
|
||||
print_info(&format!("Compiling project at {}", str_path));
|
||||
|
||||
let toml_path = if !path.exists() {
|
||||
print_error("The specified path does not exist.");
|
||||
return Err(Error::PathNotFoundError(path.to_path_buf()));
|
||||
} else if path.is_dir() {
|
||||
let toml_path = path.join("pack.toml");
|
||||
if !toml_path.exists() {
|
||||
print_error("The specified directory does not contain a pack.toml file.");
|
||||
return Err(Error::InvalidPackPathError(path.to_path_buf()));
|
||||
}
|
||||
toml_path
|
||||
} else if path.is_file()
|
||||
&& path
|
||||
.file_name()
|
||||
.ok_or(Error::InvalidPackPathError(path.to_path_buf()))?
|
||||
== "pack.toml"
|
||||
{
|
||||
path.to_path_buf()
|
||||
} else {
|
||||
print_error("The specified path is neither a directory nor a pack.toml file.");
|
||||
return Err(Error::InvalidPackPathError(path.to_path_buf()));
|
||||
};
|
||||
|
||||
let toml_content = fs::read_to_string(&toml_path)?;
|
||||
let project_config = toml::from_str::<ProjectConfig>(&toml_content)?;
|
||||
|
||||
let main_path = toml_path
|
||||
.parent()
|
||||
.ok_or(Error::InvalidPackPathError(path.to_path_buf()))?
|
||||
.join("src/main.shu");
|
||||
let compiled = shulkerscript_lang::compile(&main_path)?;
|
||||
|
||||
let dist_path = toml_path
|
||||
.parent()
|
||||
.expect("Failed to get parent directory of pack.toml")
|
||||
.join("dist")
|
||||
.join(project_config.pack.name);
|
||||
|
||||
compiled.place(&dist_path)?;
|
||||
|
||||
print_info(&format!(
|
||||
"Finished compiling project to {}",
|
||||
util::to_absolute_path(&dist_path)?
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
use std::{fs, path::Path};
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
config::ProjectConfig,
|
||||
|
@ -7,14 +10,32 @@ use crate::{
|
|||
util::to_absolute_path,
|
||||
};
|
||||
|
||||
pub fn init(
|
||||
verbose: bool,
|
||||
path: &Path,
|
||||
name: Option<&str>,
|
||||
description: Option<&str>,
|
||||
#[derive(Debug, clap::Args, Clone)]
|
||||
pub struct InitArgs {
|
||||
/// The path of the folder to initialize in.
|
||||
#[clap(default_value = ".")]
|
||||
path: PathBuf,
|
||||
/// The name of the project.
|
||||
#[clap(short, long)]
|
||||
name: Option<String>,
|
||||
/// The description of the project.
|
||||
#[clap(short, long)]
|
||||
description: Option<String>,
|
||||
/// The pack format version.
|
||||
#[clap(short, long)]
|
||||
pack_format: Option<u8>,
|
||||
/// Force initialization even if the directory is not empty.
|
||||
#[clap(short, long)]
|
||||
force: bool,
|
||||
) -> Result<()> {
|
||||
}
|
||||
|
||||
pub fn init(verbose: bool, args: &InitArgs) -> Result<()> {
|
||||
let path = args.path.as_path();
|
||||
let name = args.name.as_deref();
|
||||
let description = args.description.as_deref();
|
||||
let pack_format = args.pack_format;
|
||||
let force = args.force;
|
||||
|
||||
if !path.exists() {
|
||||
print_error("The specified path does not exist.");
|
||||
Err(Error::PathNotFoundError(path.to_path_buf()))
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
use clap::ValueEnum;
|
||||
|
||||
use crate::error::Result;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, clap::Args, Clone)]
|
||||
pub struct LangDebugArgs {
|
||||
/// The path of the project to compile.
|
||||
#[clap(default_value = ".")]
|
||||
path: PathBuf,
|
||||
/// The state to dump.
|
||||
#[clap(short, long, default_value = "ast")]
|
||||
dump: DumpState,
|
||||
/// Pretty-print the output.
|
||||
#[clap(short, long)]
|
||||
pretty: bool,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Debug, Clone, Copy, Default)]
|
||||
pub enum DumpState {
|
||||
Tokens,
|
||||
#[default]
|
||||
Ast,
|
||||
Datapack,
|
||||
}
|
||||
|
||||
pub fn lang_debug(args: &LangDebugArgs) -> Result<()> {
|
||||
match args.dump {
|
||||
DumpState::Tokens => {
|
||||
let tokens = shulkerscript_lang::tokenize(&args.path)?;
|
||||
if args.pretty {
|
||||
println!("{:#?}", tokens);
|
||||
} else {
|
||||
println!("{:?}", tokens);
|
||||
}
|
||||
}
|
||||
DumpState::Ast => {
|
||||
let ast = shulkerscript_lang::parse(&args.path)?;
|
||||
if args.pretty {
|
||||
println!("{:#?}", ast);
|
||||
} else {
|
||||
println!("{:?}", ast);
|
||||
}
|
||||
}
|
||||
DumpState::Datapack => {
|
||||
let datapack = shulkerscript_lang::transpile(&args.path)?;
|
||||
if args.pretty {
|
||||
println!("{:#?}", datapack);
|
||||
} else {
|
||||
println!("{:?}", datapack);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -1,2 +1,15 @@
|
|||
mod init;
|
||||
pub use init::init;
|
||||
pub use init::{init, InitArgs};
|
||||
|
||||
mod compile;
|
||||
pub use compile::{compile, CompileArgs};
|
||||
|
||||
#[cfg(feature = "zip")]
|
||||
mod package;
|
||||
#[cfg(feature = "zip")]
|
||||
pub use package::{package, PackageArgs};
|
||||
|
||||
#[cfg(feature = "lang-debug")]
|
||||
mod lang_debug;
|
||||
#[cfg(feature = "lang-debug")]
|
||||
pub use lang_debug::{lang_debug, LangDebugArgs};
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
use crate::error::Result;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, clap::Args, Clone)]
|
||||
pub struct PackageArgs {
|
||||
/// The path of the project to package.
|
||||
#[clap(default_value = ".")]
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
pub fn package(_verbose: bool, _args: &PackageArgs) -> Result<()> {
|
||||
println!("PACKAGE");
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue