Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support warnings #2086

Merged
merged 8 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions cli/src/completions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{
cli::{GlobalOptions, Options},
error::CliResult,
};
use crate::{cli::Options, global::GlobalContext};

#[derive(clap::Parser, Debug)]
pub struct GenCompletionsCommand {
Expand All @@ -10,13 +7,12 @@ pub struct GenCompletionsCommand {
}

impl GenCompletionsCommand {
pub fn run(self, _: GlobalOptions) -> CliResult<()> {
pub fn run(self, _: &mut GlobalContext) {
clap_complete::generate(
self.shell,
&mut <Options as clap::CommandFactory>::command(),
env!("CARGO_BIN_NAME"),
&mut std::io::stdout(),
);
Ok(())
}
}
63 changes: 37 additions & 26 deletions cli/src/customize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ use nickel_lang_core::{
typ::{RecordRowF, RecordRowsIteratorItem, Type, TypeF},
};

use crate::error::{CliResult, CliUsageError, Error, UnknownFieldData};
use crate::{
error::{CliResult, CliUsageError, Error, UnknownFieldData},
input::{PrepareError, PrepareResult},
};

pub mod interface;

Expand Down Expand Up @@ -233,7 +236,7 @@ impl CustomizableFields {

pub trait Customize {
/// Customize the program with the given options.
fn customize(&self, program: Program<CBNCache>) -> CliResult<Program<CBNCache>>;
fn customize(&self, program: Program<CBNCache>) -> PrepareResult<Program<CBNCache>>;
/// Return the value of the `field` argument, if specified and if supported by the current
/// customize variant.
fn field(&self) -> Option<&String> {
Expand Down Expand Up @@ -274,7 +277,12 @@ impl CustomizeOptions {

let assignment_overrides = match assignment_overrides {
Ok(assignment_overrides) => assignment_overrides,
Err(error) => return CliResult::Err(Error::CliUsage { error, program }),
Err(error) => {
return CliResult::Err(Error::CliUsage {
error,
files: program.files(),
})
}
};

let force_overrides: Result<Vec<_>, CliUsageError> = self
Expand All @@ -300,7 +308,12 @@ impl CustomizeOptions {

let force_overrides = match force_overrides {
Ok(force_overrides) => force_overrides,
Err(error) => return CliResult::Err(Error::CliUsage { error, program }),
Err(error) => {
return CliResult::Err(Error::CliUsage {
error,
files: program.files(),
})
}
};

program.add_overrides(assignment_overrides.into_iter().chain(force_overrides));
Expand All @@ -311,25 +324,26 @@ impl CustomizeOptions {
impl CustomizeMode {
// Contains most of the actual implementation of the customizing logic for overriding, but
// doesn't set the extracted field.
fn customize_impl(&self, mut program: Program<CBNCache>) -> CliResult<Program<CBNCache>> {
fn customize_impl(&self, mut program: Program<CBNCache>) -> PrepareResult<Program<CBNCache>> {
if self.customize_mode.is_empty() {
return Ok(program);
}

let evaled = match program.eval_record_spine() {
Ok(evaled) => evaled,
// We need a `return` control-flow to be able to take `program` out
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Not anymore 🙂

Err(error) => return CliResult::Err(Error::Program { error, program }),
};
let evaled = program
.eval_record_spine()
.map_err(|error| Error::Program {
error,
files: program.files(),
})?;

let customizable_fields = CustomizableFields::new(TermInterface::from(evaled.as_ref()));
let opts = CustomizeOptions::parse_from(self.customize_mode.iter());

match opts.command {
None => opts.do_customize(customizable_fields, program),
None => Ok(opts.do_customize(customizable_fields, program)?),
Some(CustomizeCommand::List(list_command)) => {
list_command.run(&customizable_fields)?;
Err(Error::CustomizeInfoPrinted)
Err(PrepareError::EarlyReturn)
}
}
}
Expand All @@ -339,7 +353,7 @@ impl Customize for CustomizeMode {
// XXX: we should give a nice error message when someone tries to evaluate some
// expression that has unset values, telling them they can set them using
// this method
fn customize(&self, program: Program<CBNCache>) -> CliResult<Program<CBNCache>> {
fn customize(&self, program: Program<CBNCache>) -> PrepareResult<Program<CBNCache>> {
program_with_field(
self.customize_impl(program)?,
self.extract_field.field.clone(),
Expand All @@ -363,7 +377,7 @@ pub struct ExtractFieldOnly {
}

impl Customize for ExtractFieldOnly {
fn customize(&self, program: Program<CBNCache>) -> CliResult<Program<CBNCache>> {
fn customize(&self, program: Program<CBNCache>) -> PrepareResult<Program<CBNCache>> {
program_with_field(program, self.field.clone())
}

Expand All @@ -377,26 +391,23 @@ impl Customize for ExtractFieldOnly {
pub struct NoCustomizeMode;

impl Customize for NoCustomizeMode {
fn customize(&self, program: Program<CBNCache>) -> CliResult<Program<CBNCache>> {
fn customize(&self, program: Program<CBNCache>) -> PrepareResult<Program<CBNCache>> {
Ok(program)
}
}

fn program_with_field(
mut program: Program<CBNCache>,
field: Option<String>,
) -> CliResult<Program<CBNCache>> {
) -> PrepareResult<Program<CBNCache>> {
if let Some(field) = field {
match program.parse_field_path(field) {
Ok(field_path) => program.field = field_path,
Err(error) => {
return Err(Error::CliUsage {
error: CliUsageError::FieldPathParseError { error },
program,
});
}
}
};
program.field = program
.parse_field_path(field)
.map_err(|error| Error::CliUsage {
error: CliUsageError::FieldPathParseError { error },
files: program.files(),
})?;
}

Ok(program)
}
14 changes: 4 additions & 10 deletions cli/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ use nickel_lang_core::{
program::Program,
};

use crate::{
cli::GlobalOptions,
customize::ExtractFieldOnly,
error::{CliResult, ResultErrorExt},
input::{InputOptions, Prepare},
};
use crate::{customize::ExtractFieldOnly, global::GlobalContext, input::InputOptions};

#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, clap::ValueEnum)]
pub enum DocFormat {
Expand Down Expand Up @@ -63,12 +58,11 @@ pub struct DocCommand {
const DEFAULT_OUT_DIR: &str = ".nickel/doc/";

impl DocCommand {
pub fn run(self, global: GlobalOptions) -> CliResult<()> {
let mut program = self.input.prepare(&global)?;
self.export_doc(&mut program).report_with_program(program)
pub fn run(self, ctxt: &mut GlobalContext) {
ctxt.with_program(&self.input, |prog| self.export_doc(prog));
}

fn export_doc(self, program: &mut Program<CacheImpl>) -> Result<(), Error> {
fn export_doc(&self, program: &mut Program<CacheImpl>) -> Result<(), Error> {
let doc = program.extract_doc()?;

let (mut out, out_path): (Box<dyn std::io::Write>, Option<Cow<'_, str>>) = if self.stdout {
Expand Down
59 changes: 36 additions & 23 deletions cli/src/doctest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ use std::{collections::HashMap, io::Write as _, path::PathBuf, rc::Rc};
use comrak::{arena_tree::NodeEdge, nodes::AstNode, Arena, ComrakOptions};
use nickel_lang_core::{
cache::{Cache, ImportResolver, InputFormat, SourcePath},
error::{Error as CoreError, EvalError},
eval::{cache::CacheImpl, Closure, Environment},
error::{
report::{report_as_str, report_to_stdout, ColorOpt},
Error as CoreError, EvalError, Reporter as _,
},
eval::{
cache::{lazy::CBNCache, CacheImpl},
Closure, Environment,
},
identifier::{Ident, LocIdent},
label::Label,
match_sharedterm, mk_app, mk_fun,
Expand All @@ -24,10 +30,7 @@ use once_cell::sync::Lazy;
use regex::Regex;

use crate::{
cli::GlobalOptions,
customize::ExtractFieldOnly,
error::CliResult,
input::{InputOptions, Prepare},
color_opt_from_clap, customize::ExtractFieldOnly, global::GlobalContext, input::InputOptions,
};

#[derive(clap::Parser, Debug)]
Expand Down Expand Up @@ -163,6 +166,7 @@ fn run_tests(
errors: &mut Vec<Error>,
registry: &TestRegistry,
spine: &RichTerm,
color: ColorOpt,
) {
match spine.as_ref() {
Term::Record(data) | Term::RecRecord(data, ..) => {
Expand Down Expand Up @@ -194,7 +198,7 @@ fn run_tests(
}
Err(e) => {
if let Some(expected) = &entry.expected_error {
let message = prog.report_as_str(e);
let message = report_as_str(&mut prog.files(), e, color);
if !message.contains(expected) {
Some(ErrorKind::WrongTestFailure {
message,
Expand All @@ -221,7 +225,7 @@ fn run_tests(
path.pop();
} else if let Some(val) = field.value.as_ref() {
path.push(*id);
run_tests(path, prog, errors, registry, val);
run_tests(path, prog, errors, registry, val, color);
path.pop();
}
}
Expand All @@ -231,17 +235,29 @@ fn run_tests(
}

impl TestCommand {
pub fn run(self, global: GlobalOptions) -> CliResult<()> {
let mut program = self.input.prepare(&global)?;
pub fn run(self, ctxt: &mut GlobalContext) {
let color: ColorOpt = color_opt_from_clap(ctxt.opts.color);
let num_errors = ctxt
.with_program(&self.input, |prog| self.run_tests(prog, color))
.unwrap_or(0);

let (spine, registry) = match self.prepare_tests(&mut program) {
Ok(x) => x,
Err(error) => return Err(crate::error::Error::Program { program, error }),
};
if num_errors > 0 {
eprintln!("{num_errors} failures");
ctxt.reporter.report(crate::error::Error::FailedTests);
}
}

/// Returns the number of test failures.
fn run_tests(
&self,
program: &mut Program<CBNCache>,
color: ColorOpt,
) -> Result<usize, CoreError> {
let (spine, registry) = self.prepare_tests(program)?;

let mut path = Vec::new();
let mut errors = Vec::new();
run_tests(&mut path, &mut program, &mut errors, &registry, &spine);
run_tests(&mut path, program, &mut errors, &registry, &spine, color);

let num_errors = errors.len();
for e in errors {
Expand All @@ -262,24 +278,21 @@ impl TestCommand {
}
ErrorKind::UnexpectedFailure { error } => {
println!("test {}/{} failed", path_display, e.idx);
program.report_to_stdout(
report_to_stdout(
&mut program.files(),
error,
nickel_lang_core::error::report::ErrorFormat::Text,
color,
);
}
}
}

if num_errors > 0 {
eprintln!("{num_errors} failures");
Err(crate::error::Error::FailedTests)
} else {
Ok(())
}
Ok(num_errors)
}

fn prepare_tests(
self,
&self,
program: &mut Program<CacheImpl>,
) -> Result<(RichTerm, TestRegistry), CoreError> {
let mut registry = TestRegistry::default();
Expand Down
Loading
Loading