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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
zip = ["shulkerbox/zip"]
|
||||||
|
lang-debug = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
colored = "2.1.0"
|
colored = "2.1.0"
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
thiserror = "1.0.58"
|
thiserror = "1.0.58"
|
||||||
toml = "0.8.12"
|
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,
|
||||||
use crate::{error::Result, subcommands};
|
subcommands::{self, CompileArgs, InitArgs},
|
||||||
|
};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
|
@ -15,43 +16,27 @@ pub struct Args {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Subcommand)]
|
#[derive(Debug, Clone, Subcommand)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Initialize a new project in the current directory.
|
/// Initialize a new project.
|
||||||
Init {
|
Init(InitArgs),
|
||||||
/// The path of the folder to initialize in.
|
/// Compile the project.
|
||||||
#[clap(default_value = ".")]
|
Compile(CompileArgs),
|
||||||
path: PathBuf,
|
#[cfg(feature = "zip")]
|
||||||
/// The name of the project.
|
/// Compile and package the project.
|
||||||
#[clap(short, long)]
|
Package(subcommands::PackageArgs),
|
||||||
name: Option<String>,
|
#[cfg(feature = "lang-debug")]
|
||||||
/// The description of the project.
|
/// Compile the project and dump the intermediate state.
|
||||||
#[clap(short, long)]
|
LangDebug(subcommands::LangDebugArgs),
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
pub fn run(&self) -> Result<()> {
|
pub fn run(&self) -> Result<()> {
|
||||||
match &self.cmd {
|
match &self.cmd {
|
||||||
Command::Init {
|
Command::Init(args) => subcommands::init(self.verbose, args)?,
|
||||||
path,
|
Command::Compile(args) => subcommands::compile(self.verbose, args)?,
|
||||||
name,
|
#[cfg(feature = "zip")]
|
||||||
description,
|
Command::Package(args) => subcommands::package(self.verbose, args)?,
|
||||||
pack_format,
|
#[cfg(feature = "lang-debug")]
|
||||||
force,
|
Command::LangDebug(args) => subcommands::lang_debug(args)?,
|
||||||
} => subcommands::init(
|
|
||||||
self.verbose,
|
|
||||||
path,
|
|
||||||
name.as_deref(),
|
|
||||||
description.as_deref(),
|
|
||||||
*pack_format,
|
|
||||||
*force,
|
|
||||||
)?,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -14,6 +14,10 @@ pub enum Error {
|
||||||
NonEmptyDirectoryError(PathBuf),
|
NonEmptyDirectoryError(PathBuf),
|
||||||
#[error("An error occured because the path {0} is not a directory.")]
|
#[error("An error occured because the path {0} is not a directory.")]
|
||||||
NotDirectoryError(PathBuf),
|
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>;
|
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::{
|
use crate::{
|
||||||
config::ProjectConfig,
|
config::ProjectConfig,
|
||||||
|
@ -7,14 +10,32 @@ use crate::{
|
||||||
util::to_absolute_path,
|
util::to_absolute_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(
|
#[derive(Debug, clap::Args, Clone)]
|
||||||
verbose: bool,
|
pub struct InitArgs {
|
||||||
path: &Path,
|
/// The path of the folder to initialize in.
|
||||||
name: Option<&str>,
|
#[clap(default_value = ".")]
|
||||||
description: Option<&str>,
|
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>,
|
pack_format: Option<u8>,
|
||||||
|
/// Force initialization even if the directory is not empty.
|
||||||
|
#[clap(short, long)]
|
||||||
force: bool,
|
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() {
|
if !path.exists() {
|
||||||
print_error("The specified path does not exist.");
|
print_error("The specified path does not exist.");
|
||||||
Err(Error::PathNotFoundError(path.to_path_buf()))
|
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;
|
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