1
1
mirror of https://github.com/tweag/nickel.git synced 2024-07-07 08:26:29 +03:00

Allow other formats for singleton input (#1901) (#1902)

Guess input format based on extension similarly like in multiple input case.
This commit is contained in:
Jakub A. G 2024-05-07 10:33:28 +02:00 committed by GitHub
parent 07cd7197e1
commit aca39eff18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 33 additions and 56 deletions

View File

@ -58,6 +58,14 @@ impl InputFormat {
_ => None,
}
}
/// Renturns an [InputFormat] based on the extension of a source path.
pub fn from_source_path(source_path: &SourcePath) -> Option<InputFormat> {
if let SourcePath::Path(p) = source_path {
Self::from_path(p)
} else {
None
}
}
}
/// File and terms cache.
@ -456,50 +464,10 @@ impl Cache {
}
}
/// Parse a source and populate the corresponding entry in the cache, or do nothing if the
/// entry has already been parsed. This function is error tolerant: parts of the source which
/// result in parse errors are parsed as [`crate::term::Term::ParseError`] and the
/// corresponding error messages are collected and returned.
///
/// The `Err` part of the result corresponds to non-recoverable errors.
fn parse_lax(&mut self, file_id: FileId) -> Result<CacheOp<ParseErrors>, ParseError> {
if let Some(TermEntry { parse_errs, .. }) = self.terms.get(&file_id) {
Ok(CacheOp::Cached(parse_errs.clone()))
} else {
let (term, parse_errs) = self.parse_nocache(file_id)?;
self.terms.insert(
file_id,
TermEntry {
term,
state: EntryState::Parsed,
parse_errs: parse_errs.clone(),
},
);
Ok(CacheOp::Done(parse_errs))
}
}
/// Parse a source and populate the corresponding entry in the cache, or do
/// nothing if the entry has already been parsed. This function is error
/// tolerant if `self.error_tolerant` is `true`.
pub fn parse(&mut self, file_id: FileId) -> Result<CacheOp<ParseErrors>, ParseErrors> {
let result = self.parse_lax(file_id);
match self.error_tolerance {
ErrorTolerance::Tolerant => result.map_err(|err| err.into()),
ErrorTolerance::Strict => match result? {
CacheOp::Done(e) | CacheOp::Cached(e) if !e.no_errors() => Err(e),
CacheOp::Done(_) => Ok(CacheOp::Done(ParseErrors::none())),
CacheOp::Cached(_) => Ok(CacheOp::Cached(ParseErrors::none())),
},
}
}
/// Parse a source and populate the corresponding entry in the cache, or do
/// nothing if the entry has already been parsed. Support multiple formats.
/// This function is always error tolerant, independently from `self.error_tolerant`.
fn parse_multi_lax(
fn parse_lax(
&mut self,
file_id: FileId,
format: InputFormat,
@ -523,12 +491,12 @@ impl Cache {
/// Parse a source and populate the corresponding entry in the cache, or do
/// nothing if the entry has already been parsed. Support multiple formats.
/// This function is error tolerant if `self.error_tolerant` is `true`.
pub fn parse_multi(
pub fn parse(
&mut self,
file_id: FileId,
format: InputFormat,
) -> Result<CacheOp<ParseErrors>, ParseErrors> {
let result = self.parse_multi_lax(file_id, format);
let result = self.parse_lax(file_id, format);
match self.error_tolerance {
ErrorTolerance::Tolerant => result.map_err(|err| err.into()),
@ -902,7 +870,12 @@ impl Cache {
) -> Result<CacheOp<()>, Error> {
let mut result = CacheOp::Cached(());
if let CacheOp::Done(_) = self.parse(file_id)? {
let format = self
.file_paths
.get(&file_id)
.and_then(InputFormat::from_source_path)
.unwrap_or_default();
if let CacheOp::Done(_) = self.parse(file_id, format)? {
result = CacheOp::Done(());
}
@ -1134,7 +1107,7 @@ impl Cache {
.collect();
for (_, file_id) in file_ids.iter() {
self.parse(*file_id)?;
self.parse(*file_id, InputFormat::Nickel)?;
}
self.stdlib_ids.replace(file_ids);
Ok(CacheOp::Done(()))
@ -1371,7 +1344,7 @@ impl ImportResolver for Cache {
self.rev_imports.entry(file_id).or_default().insert(parent);
}
self.parse_multi(file_id, format)
self.parse(file_id, format)
.map_err(|err| ImportError::ParseErrors(err, *pos))?;
Ok((result, file_id))

View File

@ -371,7 +371,7 @@ impl<EC: EvalCache> Program<EC> {
pub fn parse(&mut self) -> Result<RichTerm, Error> {
self.vm
.import_resolver_mut()
.parse(self.main_id)
.parse(self.main_id, InputFormat::Nickel)
.map_err(Error::ParseErrors)?;
Ok(self
.vm
@ -496,7 +496,9 @@ impl<EC: EvalCache> Program<EC> {
/// Load, parse, and typecheck the program and the standard library, if not already done.
pub fn typecheck(&mut self) -> Result<(), Error> {
self.vm.import_resolver_mut().parse(self.main_id)?;
self.vm
.import_resolver_mut()
.parse(self.main_id, InputFormat::Nickel)?;
self.vm.import_resolver_mut().load_stdlib()?;
let initial_env = self.vm.import_resolver().mk_type_ctxt().expect(
"program::typecheck(): \

View File

@ -6,7 +6,7 @@
//! Dually, the frontend is the user-facing part, which may be a CLI, a web application, a
//! jupyter-kernel (which is not exactly user-facing, but still manages input/output and
//! formatting), etc.
use crate::cache::{Cache, Envs, ErrorTolerance, SourcePath};
use crate::cache::{Cache, Envs, ErrorTolerance, InputFormat, SourcePath};
use crate::error::{
report::{self, ColorOpt, ErrorFormat},
Error, EvalError, IOError, IntoDiagnostics, ParseError, ParseErrors, ReplError,
@ -232,7 +232,9 @@ impl<EC: EvalCache> Repl for ReplImpl<EC> {
.import_resolver_mut()
.add_file(OsString::from(path.as_ref()))
.map_err(IOError::from)?;
self.vm.import_resolver_mut().parse(file_id)?;
self.vm
.import_resolver_mut()
.parse(file_id, InputFormat::Nickel)?;
let term = self.vm.import_resolver().get_owned(file_id).unwrap();
let pos = term.pos;

View File

@ -8,7 +8,7 @@
use std::path::PathBuf;
use nickel_lang_core::{
cache::SourcePath,
cache::{InputFormat, SourcePath},
parser::lexer::{self, NormalToken, SpannedToken, Token},
position::RawSpan,
term::{RichTerm, Term},
@ -102,7 +102,7 @@ fn resolve_imports(rt: RichTerm, world: &mut World) -> RichTerm {
} = import_resolution::tolerant::resolve_imports(rt, &mut world.cache);
for id in resolved_ids {
if world.cache.parse(id).is_ok() {
if world.cache.parse(id, InputFormat::Nickel).is_ok() {
// If a new input got imported in an incomplete term, try to typecheck
// (and build lookup tables etc.) for it, but don't issue diagnostics.
let _ = world.typecheck(id);

View File

@ -8,7 +8,7 @@ use codespan::FileId;
use lsp_server::{ErrorCode, ResponseError};
use lsp_types::Url;
use nickel_lang_core::{
cache::{Cache, CacheError, ErrorTolerance, SourcePath},
cache::{Cache, CacheError, ErrorTolerance, InputFormat, SourcePath},
error::{ImportError, IntoDiagnostics},
position::{RawPos, RawSpan},
term::{record::FieldMetadata, RichTerm, Term, UnaryOp},
@ -160,7 +160,7 @@ impl World {
file_id: FileId,
) -> Result<Vec<SerializableDiagnostic>, Vec<SerializableDiagnostic>> {
self.cache
.parse(file_id)
.parse(file_id, InputFormat::Nickel)
.map(|nonfatal| self.lsp_diagnostics(file_id, nonfatal.inner()))
.map_err(|fatal| self.lsp_diagnostics(file_id, fatal))
}

View File

@ -171,7 +171,7 @@ macro_rules! ncl_bench_group {
(name = $group_name:ident; config = $config:expr; $($b:tt),+ $(,)*) => {
pub fn $group_name() {
use nickel_lang_core::{
cache::{Envs, Cache, ErrorTolerance, ImportResolver},
cache::{Envs, Cache, ErrorTolerance, ImportResolver, InputFormat},
eval::{VirtualMachine, cache::{CacheImpl, Cache as EvalCache}},
transform::import_resolution::strict::resolve_imports,
error::report::{report, ColorOpt, ErrorFormat},
@ -194,7 +194,7 @@ macro_rules! ncl_bench_group {
.unwrap()
.transformed_term;
if bench.eval_mode == $crate::bench::EvalMode::TypeCheck {
cache.parse(id).unwrap();
cache.parse(id, InputFormat::Nickel).unwrap();
cache.resolve_imports(id).unwrap();
}
(cache, id, t)