diff --git a/layouts/cli/src/main.rs b/layouts/cli/src/main.rs index 46d28c4..c038182 100644 --- a/layouts/cli/src/main.rs +++ b/layouts/cli/src/main.rs @@ -58,12 +58,27 @@ fn load_file(files: &SimpleFiles, file_id: usize) -> bool { Ok(_layout) => true, Err(e) => { let span = code_map.get(e.position()).unwrap().span; + + let mut labels = + vec![Label::primary(file_id, span).with_message(e.to_string())]; + + let mut notes = Vec::new(); + for hint in e.hints() { + match hint.position() { + Some(i) => { + let span = code_map.get(i).unwrap().span; + labels.push( + Label::secondary(file_id, span).with_message(hint.to_string()), + ) + } + None => notes.push(hint.to_string()), + } + } + let diagnostic = Diagnostic::error() .with_message("Layout syntax error") - .with_labels(vec![ - Label::primary(file_id, span).with_message(e.to_string()) - ]) - .with_notes(e.hints().into_iter().map(|h| h.to_string()).collect()); + .with_labels(labels) + .with_notes(notes); let writer = StandardStream::stderr(ColorChoice::Always); let config = codespan_reporting::term::Config::default(); diff --git a/layouts/src/abs/syntax/mod.rs b/layouts/src/abs/syntax/mod.rs index 006b246..173bc4e 100644 --- a/layouts/src/abs/syntax/mod.rs +++ b/layouts/src/abs/syntax/mod.rs @@ -74,14 +74,12 @@ pub enum Error { impl Error { pub fn duplicate<'a>( key: &str, - ) -> impl '_ - + FnOnce( - json_syntax::object::Duplicate>, - ) -> Self { + ) -> impl '_ + FnOnce(json_syntax::object::Duplicate>) -> Self + { move |e| Self::DuplicateEntry { - offset: e.0.offset, + offset: e.0.value.key.offset, key: key.to_owned(), - other_offset: e.1.offset, + other_offset: e.1.value.key.offset, } } @@ -105,6 +103,9 @@ impl Error { pub fn hints(&self) -> Vec { match self { + Self::DuplicateEntry { other_offset, .. } => { + vec![ErrorHint::DuplicateEntry(*other_offset)] + } Self::InvalidType { expected, found, .. } => vec![ @@ -147,6 +148,16 @@ impl From> for Error { pub enum ErrorHint<'a> { ExpectedType(ExpectedType), FoundType(&'a str), + DuplicateEntry(usize), +} + +impl<'a> ErrorHint<'a> { + pub fn position(&self) -> Option { + match self { + Self::DuplicateEntry(offset) => Some(*offset), + _ => None, + } + } } impl<'a> fmt::Display for ErrorHint<'a> { @@ -174,6 +185,7 @@ impl<'a> fmt::Display for ErrorHint<'a> { } }, Self::FoundType(ty) => write!(f, "found type `{ty}`"), + Self::DuplicateEntry(_) => write!(f, "also defined here"), } } } @@ -232,14 +244,18 @@ pub(crate) fn get_entry( where T::Error: Into, { - let value = object - .get_unique_mapped(code_map, offset, key) + let entry = object + .get_unique_mapped_entry(code_map, offset, key) .map_err(Error::duplicate(key))?; - match value { - Some(value) => { - let t = T::try_from_json_syntax_at(value.value, code_map, value.offset) - .map_err(Into::into)?; + match entry { + Some(entry) => { + let t = T::try_from_json_syntax_at( + entry.value.value.value, + code_map, + entry.value.value.offset, + ) + .map_err(Into::into)?; Ok(Some(t)) } None => Ok(None), @@ -255,13 +271,14 @@ pub(crate) fn require_entry( where T::Error: Into, { - let value = object - .get_unique_mapped(code_map, offset, key) + let entry = object + .get_unique_mapped_entry(code_map, offset, key) .map_err(Error::duplicate(key))?; - match value { - Some(value) => { - T::try_from_json_syntax_at(value.value, code_map, value.offset).map_err(Into::into) + match entry { + Some(entry) => { + T::try_from_json_syntax_at(entry.value.value.value, code_map, entry.value.value.offset) + .map_err(Into::into) } None => Err(Error::MissingRequiredEntry { offset, @@ -275,17 +292,18 @@ pub(crate) fn require_type<'a>( code_map: &json_syntax::CodeMap, offset: usize, ) -> Result, Error> { - let ty = object - .get_unique_mapped(code_map, offset, "type") + let entry = object + .get_unique_mapped_entry(code_map, offset, "type") .map_err(Error::duplicate("type"))? .ok_or(Error::MissingType(offset))?; - match ty.value { - json_syntax::Value::String(found) => { - Ok(json_syntax::code_map::Mapped::new(ty.offset, found)) - } + match entry.value.value.value { + json_syntax::Value::String(found) => Ok(json_syntax::code_map::Mapped::new( + entry.value.value.offset, + found, + )), other => Err(Error::Unexpected { - offset: ty.offset, + offset: entry.value.value.offset, expected: json_syntax::KindSet::STRING, found: other.kind(), }),