diff --git a/Cargo.lock b/Cargo.lock index 11c756464..71f290698 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,7 @@ dependencies = [ "build-helper", "chrono", "clap", + "clap_complete", "colored", "glob", "heraclitus-compiler", @@ -74,9 +75,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" @@ -205,9 +206,9 @@ checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" [[package]] name = "clap" -version = "4.5.8" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -215,9 +216,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.8" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -225,11 +226,20 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2 1.0.86", diff --git a/Cargo.toml b/Cargo.toml index 3c501685c..dbe10cedf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,8 @@ copyright = "GPLv3" [dependencies] amber-meta = { path = "meta" } chrono = "0.4.38" -clap = { version = "4.4.18", features = ["derive"] } +clap = { version = "4.5.20", features = ["derive"] } +clap_complete = "4.5.36" colored = "2.0.0" glob = "0.3" heraclitus-compiler = "1.8.1" diff --git a/src/compiler.rs b/src/compiler.rs index 44dddb681..bb1204fc6 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -4,7 +4,7 @@ use crate::modules::block::Block; use crate::translate::check_all_blocks; use crate::translate::module::TranslateModule; use crate::utils::{ParserMetadata, TranslateMetadata}; -use crate::{rules, Cli}; +use crate::rules; use postprocessor::PostProcessor; use chrono::prelude::*; use colored::Colorize; @@ -24,20 +24,36 @@ const NO_CODE_PROVIDED: &str = "No code has been provided to the compiler"; const AMBER_DEBUG_PARSER: &str = "AMBER_DEBUG_PARSER"; const AMBER_DEBUG_TIME: &str = "AMBER_DEBUG_TIME"; +pub struct CompilerOptions { + pub no_proc: Vec, + pub minify: bool, +} + +impl Default for CompilerOptions { + fn default() -> Self { + let no_proc = vec![String::from("*")]; + Self { no_proc, minify: false } + } +} + +impl CompilerOptions { + pub fn from_args(no_proc: &[String], minify: bool) -> Self { + let no_proc = no_proc.to_owned(); + Self { no_proc, minify } + } +} + pub struct AmberCompiler { pub cc: Compiler, pub path: Option, - pub cli_opts: Cli, + pub options: CompilerOptions, } impl AmberCompiler { - pub fn new(code: String, path: Option, cli_opts: Cli) -> AmberCompiler { - AmberCompiler { - cc: Compiler::new("Amber", rules::get_rules()), - path, - cli_opts, - } - .load_code(AmberCompiler::comment_shebang(code)) + pub fn new(code: String, path: Option, options: CompilerOptions) -> AmberCompiler { + let cc = Compiler::new("Amber", rules::get_rules()); + let compiler = AmberCompiler { cc, path, options }; + compiler.load_code(AmberCompiler::comment_shebang(code)) } fn comment_shebang(code: String) -> String { @@ -91,14 +107,9 @@ impl AmberCompiler { } } - pub fn parse( - &self, - tokens: Vec, - is_docs_gen: bool, - ) -> Result<(Block, ParserMetadata), Message> { + pub fn parse(&self, tokens: Vec) -> Result<(Block, ParserMetadata), Message> { let code = self.cc.code.as_ref().expect(NO_CODE_PROVIDED).clone(); let mut meta = ParserMetadata::new(tokens, self.path.clone(), Some(code)); - meta.is_docs_gen = is_docs_gen; if let Err(Failure::Loud(err)) = check_all_blocks(&meta) { return Err(err); } @@ -150,7 +161,7 @@ impl AmberCompiler { pub fn translate(&self, block: Block, meta: ParserMetadata) -> Result { let ast_forest = self.get_sorted_ast_forest(block, &meta); - let mut meta_translate = TranslateMetadata::new(meta, &self.cli_opts); + let mut meta_translate = TranslateMetadata::new(meta, &self.options); let time = Instant::now(); let mut result = vec![]; for (_path, block) in ast_forest { @@ -167,7 +178,7 @@ impl AmberCompiler { let mut result = result.join("\n") + "\n"; - let filters = self.cli_opts.no_proc.iter() + let filters = self.options.no_proc.iter() .map(|x| WildMatchPattern::new(x)) .collect(); let postprocessors = PostProcessor::filter_default(filters); @@ -185,13 +196,10 @@ impl AmberCompiler { }; } + let now = Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); let header = include_str!("header.sh") .replace("{{ version }}", env!("CARGO_PKG_VERSION")) - .replace("{{ date }}", Local::now() - .format("%Y-%m-%d %H:%M:%S") - .to_string() - .as_str() - ); + .replace("{{ date }}", now.as_str()); Ok(format!("{}{}", header, result)) } @@ -255,15 +263,21 @@ impl AmberCompiler { pub fn compile(&self) -> Result<(Vec, String), Message> { let tokens = self.tokenize()?; - let (block, meta) = self.parse(tokens, false)?; + let (block, meta) = self.parse(tokens)?; let messages = meta.messages.clone(); let code = self.translate(block, meta)?; Ok((messages, code)) } - pub fn execute(code: String, flags: &[String]) -> Result { + pub fn execute(mut code: String, args: Vec) -> Result { if let Some(mut command) = Self::find_bash() { - let code = format!("set -- {};\n{}", flags.join(" "), code); + if !args.is_empty() { + let args = args.into_iter() + .map(|arg| arg.replace("\"", "\\\"")) + .map(|arg| format!("\"{arg}\"")) + .collect::>(); + code = format!("set -- {}\n{}", args.join(" "), code); + } command.arg("-c").arg(code).spawn()?.wait() } else { let error = std::io::Error::new(ErrorKind::NotFound, "Failed to find Bash"); @@ -271,16 +285,17 @@ impl AmberCompiler { } } - pub fn generate_docs(&self, output: String) -> Result<(), Message> { + pub fn generate_docs(&self, output: String, usage: bool) -> Result<(), Message> { let tokens = self.tokenize()?; - let (block, meta) = self.parse(tokens, true)?; + let (block, mut meta) = self.parse(tokens)?; + meta.doc_usage = usage; self.document(block, meta, output); Ok(()) } #[cfg(test)] pub fn test_eval(&mut self) -> Result { - self.cli_opts.no_proc = vec!["*".into()]; + self.options.no_proc = vec!["*".into()]; self.compile().map_or_else(Err, |(_, code)| { if let Some(mut command) = Self::find_bash() { let child = command.arg("-c").arg::<&str>(code.as_ref()).output().unwrap(); diff --git a/src/main.rs b/src/main.rs index 5b10fd2fb..3b8b591d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,69 +9,176 @@ mod utils; #[cfg(test)] pub mod tests; -use crate::compiler::AmberCompiler; -use clap::Parser; +use crate::compiler::{AmberCompiler, CompilerOptions}; +use clap::{Args, CommandFactory, Parser, Subcommand}; +use clap_complete::Shell; use colored::Colorize; use heraclitus_compiler::prelude::*; use std::error::Error; -use std::fs; use std::io::{prelude::*, stdin}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::process::Command; +use std::{fs, io}; #[derive(Parser, Clone, Debug)] #[command(version, arg_required_else_help(true))] -#[derive(Default)] -pub struct Cli { - #[arg(help = "'-' to read from stdin")] +struct Cli { + #[command(subcommand)] + command: Option, + + /// Input filename ('-' to read from stdin) input: Option, - #[arg(help = "'-' to output to stdout, '--silent' to discard")] - output: Option, + /// Arguments passed to Amber script + #[arg(trailing_var_arg = true)] + args: Vec, + + /// Disable a postprocessor + /// Available postprocessors: 'shfmt', 'bshchk' + /// To select multiple, pass multiple times with different values + /// Argument also supports a wilcard match, like "*" or "s*mt" + #[arg(long, verbatim_doc_comment)] + no_proc: Vec, +} + +#[derive(Subcommand, Clone, Debug)] +enum CommandKind { + /// Execute Amber code fragment + Eval(EvalCommand), + /// Execute Amber script + Run(RunCommand), + /// Check Amber script for errors + Check(CheckCommand), + /// Compile Amber script to Bash + Build(BuildCommand), + /// Generate Amber script documentation + Docs(DocsCommand), + /// Generate Bash completion script + Completion, +} + +#[derive(Args, Clone, Debug)] +struct EvalCommand { /// Code to evaluate - #[arg(short, long)] - eval: Option, + code: String, +} + +#[derive(Args, Clone, Debug)] +struct RunCommand { + /// Input filename ('-' to read from stdin) + input: PathBuf, + + /// Arguments passed to Amber script + #[arg(trailing_var_arg = true)] + args: Vec, + + /// Disable a postprocessor + /// Available postprocessors: 'shfmt', 'bshchk' + /// To select multiple, pass multiple times with different values + /// Argument also supports a wilcard match, like "*" or "s*mt" + #[arg(long, verbatim_doc_comment)] + no_proc: Vec, +} + +#[derive(Args, Clone, Debug)] +struct CheckCommand { + /// Input filename ('-' to read from stdin) + input: PathBuf, + + /// Disable a postprocessor + /// Available postprocessors: 'shfmt', 'bshchk' + /// To select multiple, pass multiple times with different values + /// Argument also supports a wilcard match, like "*" or "s*mt" + #[arg(long, verbatim_doc_comment)] + no_proc: Vec, +} + +#[derive(Args, Clone, Debug)] +struct BuildCommand { + /// Input filename ('-' to read from stdin) + input: PathBuf, + + /// Output filename ('-' to output to stdout) + output: Option, - /// Generate docs - /// (OUTPUT is dir instead, default: `docs/` if missing it will generate the folder) - #[arg(long)] - docs: bool, - /// Disable a postprocessor - /// Available postprocessors: shfmt, bshchk - /// To select multiple, pass this argument multiple times with different values. - /// This argument also supports a wilcard match, like "*" or "s*mt" + /// Available postprocessors: 'shfmt', 'bshchk' + /// To select multiple, pass multiple times with different values + /// Argument also supports a wilcard match, like "*" or "s*mt" #[arg(long, verbatim_doc_comment)] no_proc: Vec, - /// Minify the resulting code + /// Minify the output file #[arg(long)] minify: bool, } +#[derive(Args, Clone, Debug)] +struct DocsCommand { + /// Input filename ('-' to read from stdin) + input: PathBuf, + + /// Output directory (relative to input file, default 'docs') + output: Option, + + /// Show standard library usage in documentation + #[arg(long)] + usage: bool, +} + fn main() -> Result<(), Box> { let cli = Cli::parse(); - if cli.docs { - handle_docs(cli)?; - } else if let Some(ref code) = cli.eval { - handle_eval(code.to_string(), cli)?; - } else { - handle_compile(cli)?; + if let Some(command) = cli.command { + match command { + CommandKind::Eval(command) => { + handle_eval(command)?; + } + CommandKind::Run(command) => { + let options = CompilerOptions::from_args(&command.no_proc, false); + let (code, messages) = compile_input(command.input, options); + execute_output(code, command.args, messages)?; + } + CommandKind::Check(command) => { + let options = CompilerOptions::from_args(&command.no_proc, false); + compile_input(command.input, options); + } + CommandKind::Build(command) => { + let output = create_output(&command); + let options = CompilerOptions::from_args(&command.no_proc, command.minify); + let (code, _) = compile_input(command.input, options); + write_output(output, code); + } + CommandKind::Docs(command) => { + handle_docs(command)?; + } + CommandKind::Completion => { + handle_completion(); + } + } + } else if let Some(input) = cli.input { + let options = CompilerOptions::from_args(&cli.no_proc, false); + let (code, messages) = compile_input(input, options); + execute_output(code, cli.args, messages)?; } Ok(()) } -fn handle_compile(cli: Cli) -> Result<(), Box> { - let input = if let Some(input) = cli.input.clone() { - String::from(input.to_string_lossy().trim()) +fn create_output(command: &BuildCommand) -> PathBuf { + if let Some(output) = &command.output { + output.clone() + } else if command.input.as_os_str() == "-" { + command.input.clone() } else { - return Ok(()); - }; + command.input.with_extension("sh") + } +} - let code = if input == "-" { - let mut buf = String::new(); - match stdin().read_to_string(&mut buf) { - Ok(_) => buf, +fn compile_input(input: PathBuf, options: CompilerOptions) -> (String, bool) { + let input = input.to_string_lossy().to_string(); + let amber_code = if input == "-" { + let mut code = String::new(); + match stdin().read_to_string(&mut code) { + Ok(_) => code, Err(err) => handle_err(err), } } else { @@ -80,8 +187,8 @@ fn handle_compile(cli: Cli) -> Result<(), Box> { Err(err) => handle_err(err), } }; - - let (messages, code) = match AmberCompiler::new(code, Some(input), cli.clone()).compile() { + let compiler = AmberCompiler::new(amber_code, Some(input), options); + let (messages, bash_code) = match compiler.compile() { Ok(result) => result, Err(err) => { err.show(); @@ -89,45 +196,43 @@ fn handle_compile(cli: Cli) -> Result<(), Box> { } }; messages.iter().for_each(|m| m.show()); - // Save to the output file - let output = if let Some(output) = cli.output { - String::from(output.to_string_lossy()) - } else { - // Execute the code - (!messages.is_empty()).then(render_dash); - let exit_status = AmberCompiler::execute(code, &[])?; - std::process::exit(exit_status.code().unwrap_or(1)); - }; + (bash_code, !messages.is_empty()) +} - if output == "--silent" { - return Ok(()); +fn execute_output(code: String, args: Vec, messages: bool) -> Result<(), Box> { + if messages { + render_dash(); } + let exit_status = AmberCompiler::execute(code, args)?; + std::process::exit(exit_status.code().unwrap_or(1)); +} +fn write_output(output: PathBuf, code: String) { + let output = output.to_string_lossy().to_string(); if output == "-" { print!("{code}"); - return Ok(()); - } - - match fs::File::create(&output) { - Ok(mut file) => { - write!(file, "{}", code).unwrap(); - set_file_permission(&file, output); - } - Err(err) => { - Message::new_err_msg(err.to_string()).show(); - std::process::exit(1); + } else { + match fs::File::create(&output) { + Ok(mut file) => { + write!(file, "{}", code).unwrap(); + set_file_permission(&file, output); + } + Err(err) => { + Message::new_err_msg(err.to_string()).show(); + std::process::exit(1); + } } } - - Ok(()) } -fn handle_eval(code: String, cli: Cli) -> Result<(), Box> { - match AmberCompiler::new(code, None, cli).compile() { +fn handle_eval(command: EvalCommand) -> Result<(), Box> { + let options = CompilerOptions::default(); + let compiler = AmberCompiler::new(command.code, None, options); + match compiler.compile() { Ok((messages, code)) => { messages.iter().for_each(|m| m.show()); (!messages.is_empty()).then(render_dash); - let exit_status = AmberCompiler::execute(code, &[])?; + let exit_status = AmberCompiler::execute(code, vec![])?; std::process::exit(exit_status.code().unwrap_or(1)); } Err(err) => { @@ -137,39 +242,20 @@ fn handle_eval(code: String, cli: Cli) -> Result<(), Box> { } } -fn handle_docs(cli: Cli) -> Result<(), Box> { - let input = if let Some(ref input) = cli.input { - let path = Path::new(input); - if !path.exists() { - Message::new_err_msg(format!( - "Amber file doesn't exist: `{}`.", input.to_string_lossy() - )) - .show(); - std::process::exit(1); - } - String::from(input.to_string_lossy()) - } else { - Message::new_err_msg( - "You need to provide a path to an entry file to generate the documentation", - ) - .show(); - std::process::exit(1); - }; - - let output = { - let out = cli.output.clone().unwrap_or_else(|| PathBuf::from("docs")); - String::from(out.to_string_lossy()) - }; - - let code: String = match fs::read_to_string(&input) { +fn handle_docs(command: DocsCommand) -> Result<(), Box> { + let input = command.input.to_string_lossy().to_string(); + let code = match fs::read_to_string(&input) { Ok(code) => code, Err(err) => { Message::new_err_msg(err.to_string()).show(); std::process::exit(1); } }; - - match AmberCompiler::new(code, Some(input), cli).generate_docs(output) { + let options = CompilerOptions::default(); + let compiler = AmberCompiler::new(code, Some(input), options); + let output = command.output.unwrap_or_else(|| PathBuf::from("docs")); + let output = output.to_string_lossy().to_string(); + match compiler.generate_docs(output, command.usage) { Ok(_) => Ok(()), Err(err) => { err.show(); @@ -178,6 +264,12 @@ fn handle_docs(cli: Cli) -> Result<(), Box> { } } +fn handle_completion() { + let mut command = Cli::command(); + let name = command.get_name().to_string(); + clap_complete::generate(Shell::Bash, &mut command, name, &mut io::stdout()); +} + #[cfg(windows)] fn set_file_permission(_file: &fs::File, _output: String) { // We don't need to set permission on Windows diff --git a/src/modules/function/declaration.rs b/src/modules/function/declaration.rs index 9e9036ae4..4cf93c7b0 100644 --- a/src/modules/function/declaration.rs +++ b/src/modules/function/declaration.rs @@ -1,9 +1,6 @@ use std::collections::HashSet; -#[cfg(debug_assertions)] use std::{env, fs}; -#[cfg(debug_assertions)] use std::ffi::OsStr; -#[cfg(debug_assertions)] use std::path::Path; use heraclitus_compiler::prelude::*; @@ -278,74 +275,65 @@ impl DocumentationModule for FunctionDeclaration { fn document(&self, meta: &ParserMetadata) -> String { let mut result = vec![]; result.push(format!("## `{}`\n", self.name)); - - let references = self.create_reference(meta, &mut result); - + let references = self.create_test_references(meta, &mut result); result.push("```ab".to_string()); result.push(self.doc_signature.to_owned().unwrap()); result.push("```\n".to_string()); if let Some(comment) = &self.comment { result.push(comment.document(meta)); } - if let Some(references) = references { for reference in references { result.push(reference); } result.push("\n".to_string()); } - result.join("\n") } } impl FunctionDeclaration { - #[cfg(debug_assertions)] - fn create_reference(&self, meta: &ParserMetadata, result: &mut Vec) -> Option> { - let mut references = Vec::new(); - let exe_path = env::current_exe() - .expect("Executable path not found"); - let root_path = exe_path.parent() - .and_then(Path::parent) - .and_then(Path::parent) - .expect("Root path not found"); - let test_path = root_path.join("src") - .join("tests") - .join("stdlib"); - let lib_name = meta.context.path.as_ref() - .map(Path::new) - .and_then(Path::file_name) - .and_then(OsStr::to_str) - .map(String::from) - .unwrap_or_default(); - result.push(String::from("```ab")); - result.push(format!("import {{ {} }} from \"std/{}\"", self.name, lib_name)); - result.push(String::from("```\n")); - if test_path.exists() && test_path.is_dir() { - if let Ok(entries) = fs::read_dir(test_path) { - let pattern = format!("{}*.ab", self.name); - let pattern = glob::Pattern::new(&pattern).unwrap(); - for entry in entries.flatten() { - let path = entry.path(); - if let Some(file_name) = path.file_name().and_then(OsStr::to_str) { - if pattern.matches(file_name) { - references.push(format!("* [{}](https://github.com/amber-lang/amber/blob/master/src/tests/stdlib/{})", file_name, file_name)); + fn create_test_references(&self, meta: &ParserMetadata, result: &mut Vec) -> Option> { + if meta.doc_usage { + let mut references = Vec::new(); + let exe_path = env::current_exe() + .expect("Executable path not found"); + let root_path = exe_path.parent() + .and_then(Path::parent) + .and_then(Path::parent) + .expect("Root path not found"); + let test_path = root_path.join("src") + .join("tests") + .join("stdlib"); + let lib_name = meta.context.path.as_ref() + .map(Path::new) + .and_then(Path::file_name) + .and_then(OsStr::to_str) + .map(String::from) + .unwrap_or_default(); + result.push(String::from("```ab")); + result.push(format!("import {{ {} }} from \"std/{}\"", self.name, lib_name)); + result.push(String::from("```\n")); + if test_path.exists() && test_path.is_dir() { + if let Ok(entries) = fs::read_dir(test_path) { + let pattern = format!("{}*.ab", self.name); + let pattern = glob::Pattern::new(&pattern).unwrap(); + for entry in entries.flatten() { + let path = entry.path(); + if let Some(file_name) = path.file_name().and_then(OsStr::to_str) { + if pattern.matches(file_name) { + references.push(format!("* [{}](https://github.com/amber-lang/amber/blob/master/src/tests/stdlib/{})", file_name, file_name)); + } } } } } + if !references.is_empty() { + references.sort(); + references.insert(0, String::from("You can check the original tests for code examples:")); + return Some(references); + } } - if !references.is_empty() { - references.sort(); - references.insert(0, String::from("You can check the original tests for code examples:")); - Some(references) - } else { - None - } - } - - #[cfg(not(debug_assertions))] - fn create_reference(&self, _meta: &ParserMetadata, _result: &mut Vec) -> Option> { None } } diff --git a/src/modules/imports/import.rs b/src/modules/imports/import.rs index e318f3254..22ff44849 100644 --- a/src/modules/imports/import.rs +++ b/src/modules/imports/import.rs @@ -1,6 +1,6 @@ use std::fs; use heraclitus_compiler::prelude::*; -use crate::compiler::AmberCompiler; +use crate::compiler::{AmberCompiler, CompilerOptions}; use crate::docs::module::DocumentationModule; use crate::modules::block::Block; use crate::modules::variable::variable_name_extensions; @@ -8,7 +8,6 @@ use crate::stdlib; use crate::utils::context::{Context, FunctionDecl}; use crate::utils::{ParserMetadata, TranslateMetadata}; use crate::translate::module::TranslateModule; -use crate::Cli; use super::import_string::ImportString; #[derive(Debug, Clone)] @@ -88,16 +87,18 @@ impl Import { } } - fn handle_import(&mut self, meta: &mut ParserMetadata, imported_code: String) -> SyntaxResult { + fn handle_import(&mut self, meta: &mut ParserMetadata, code: String) -> SyntaxResult { // If the import was already cached, we don't need to recompile it match meta.import_cache.get_import_pub_funs(Some(self.path.value.clone())) { Some(pub_funs) => self.handle_export(meta, pub_funs), - None => self.handle_compile_code(meta, imported_code) + None => self.handle_compile_code(meta, code) } } - fn handle_compile_code(&mut self, meta: &mut ParserMetadata, imported_code: String) -> SyntaxResult { - match AmberCompiler::new(imported_code.clone(), Some(self.path.value.clone()), Cli::default()).tokenize() { + fn handle_compile_code(&mut self, meta: &mut ParserMetadata, code: String) -> SyntaxResult { + let options = CompilerOptions::default(); + let compiler = AmberCompiler::new(code, Some(self.path.value.clone()), options); + match compiler.tokenize() { Ok(tokens) => { let mut block = Block::new(); // Save snapshot of current file @@ -167,9 +168,8 @@ impl SyntaxModule for Import { syntax(meta, &mut self.path)?; // Import code from file or standard library self.add_import(meta, &self.path.value.clone())?; - let imported_code = self.resolve_import(meta)?; - - self.handle_import(meta, imported_code)?; + let code = self.resolve_import(meta)?; + self.handle_import(meta, code)?; Ok(()) } } diff --git a/src/tests/cli.rs b/src/tests/cli.rs index 97b1c6c2c..5da5f9074 100644 --- a/src/tests/cli.rs +++ b/src/tests/cli.rs @@ -25,15 +25,14 @@ fn bash_error_exit_code() -> Result<(), Box> { // Changes locale to default to prevent locale-specific error messages. cmd.env("LC_ALL", "C") + .arg("run") .arg("--no-proc") .arg("*") .arg(file.path()); cmd.assert() .failure() - .stderr(predicate::str::contains( - "notexistingcommand: command not found", - )) + .stderr(predicate::str::contains("notexistingcommand: command not found")) .code(127); Ok(()) diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 2e7d26a24..1b62c2fb5 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,5 +1,4 @@ -use crate::compiler::AmberCompiler; -use crate::Cli; +use crate::compiler::{AmberCompiler, CompilerOptions}; extern crate test_generator; use itertools::Itertools; use std::fs; @@ -15,25 +14,22 @@ mod validity; /// compare the output of the given code with the expected output pub fn test_amber(code: impl Into, result: impl AsRef) { - match AmberCompiler::new(code.into(), None, Cli::default()).test_eval() { + let options = CompilerOptions::default(); + let mut compiler = AmberCompiler::new(code.into(), None, options); + match compiler.test_eval() { Ok(eval_result) => assert_eq!( eval_result.trim_end_matches('\n'), - result.as_ref().trim_end_matches('\n') + result.as_ref().trim_end_matches('\n'), ), Err(err) => panic!("ERROR: {}", err.message.unwrap()), } } pub fn compile_code>(code: T) -> String { - let cli = Cli { - no_proc: vec!["*".into()], - ..Cli::default() - }; - - AmberCompiler::new(code.into(), None, cli) - .compile() - .unwrap() - .1 + let options = CompilerOptions::default(); + let compiler = AmberCompiler::new(code.into(), None, options); + let (_, code) = compiler.compile().unwrap(); + code } pub fn eval_bash>(code: T) -> (String, String) { diff --git a/src/utils/metadata/parser.rs b/src/utils/metadata/parser.rs index 9a41f4a04..46e3acf34 100644 --- a/src/utils/metadata/parser.rs +++ b/src/utils/metadata/parser.rs @@ -28,8 +28,8 @@ pub struct ParserMetadata { pub context: Context, /// List of all failure messages pub messages: Vec, - /// Determines if we are generating documentation - pub is_docs_gen: bool + /// Show standard library usage in documentation + pub doc_usage: bool, } impl ParserMetadata { @@ -170,7 +170,7 @@ impl Metadata for ParserMetadata { var_id: 0, context: Context::new(path, tokens), messages: Vec::new(), - is_docs_gen: false + doc_usage: false, } } diff --git a/src/utils/metadata/translate.rs b/src/utils/metadata/translate.rs index ea1770057..d3fdac5a7 100644 --- a/src/utils/metadata/translate.rs +++ b/src/utils/metadata/translate.rs @@ -1,6 +1,8 @@ use std::collections::VecDeque; -use crate::{translate::compute::ArithType, utils::function_cache::FunctionCache, Cli}; +use crate::compiler::CompilerOptions; +use crate::translate::compute::ArithType; +use crate::utils::function_cache::FunctionCache; use crate::utils::function_metadata::FunctionMetadata; use super::ParserMetadata; @@ -31,7 +33,7 @@ pub struct TranslateMetadata { } impl TranslateMetadata { - pub fn new(meta: ParserMetadata, cli: &Cli) -> Self { + pub fn new(meta: ParserMetadata, options: &CompilerOptions) -> Self { TranslateMetadata { arith_module: ArithType::BcSed, fun_cache: meta.fun_cache, @@ -42,7 +44,7 @@ impl TranslateMetadata { eval_ctx: false, silenced: false, indent: -1, - minify: cli.minify + minify: options.minify, } }