dsn: display line, column when printing error

This commit is contained in:
Mikolaj Wielgus 2024-03-03 10:53:42 +00:00
parent 7d0a17febd
commit ec799fb107
2 changed files with 74 additions and 42 deletions

View File

@ -1,11 +1,13 @@
use std::fmt;
use serde::de::{self, DeserializeSeed, SeqAccess, Visitor}; use serde::de::{self, DeserializeSeed, SeqAccess, Visitor};
use serde::Deserialize; use serde::Deserialize;
use thiserror::Error; use thiserror::Error;
type Result<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, DsnDeError>;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum Error { pub enum DsnDeError {
#[error("{0}")] #[error("{0}")]
Message(String), Message(String),
#[error("unexpected EOF")] #[error("unexpected EOF")]
@ -22,20 +24,31 @@ pub enum Error {
ExpectedOpeningParen, ExpectedOpeningParen,
#[error("expected closing parenthesis")] #[error("expected closing parenthesis")]
ExpectedClosingParen, ExpectedClosingParen,
#[error("wrong struct, expected {0}")] #[error("wrong keyword: expected {0}, got {1}")]
ExpectedStruct(&'static str), WrongKeyword(&'static str, String),
} }
impl de::Error for Error { impl de::Error for DsnDeError {
fn custom<T: std::fmt::Display>(msg: T) -> Self { fn custom<T: std::fmt::Display>(msg: T) -> Self {
Error::Message(msg.to_string()) DsnDeError::Message(msg.to_string())
} }
} }
struct Deserializer<'de> { #[derive(Debug)]
input: &'de str, pub struct DsnContext {
line: usize, line: usize,
column: usize, column: usize,
}
impl fmt::Display for DsnContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "line {0}, column {1}", self.line, self.column)
}
}
pub struct Deserializer<'de> {
input: &'de str,
pub context: DsnContext,
string_quote: Option<char>, string_quote: Option<char>,
space_in_quoted_tokens: bool, space_in_quoted_tokens: bool,
@ -52,11 +65,10 @@ enum ReconfigIncoming {
} }
impl<'de> Deserializer<'de> { impl<'de> Deserializer<'de> {
fn from_str(input: &'de str) -> Self { pub fn from_str(input: &'de str) -> Self {
Self { Self {
input, input,
line: 0, context: DsnContext { line: 0, column: 0 },
column: 0,
string_quote: None, string_quote: None,
space_in_quoted_tokens: false, space_in_quoted_tokens: false,
@ -80,17 +92,17 @@ impl<'de> Deserializer<'de> {
} }
fn peek(&mut self) -> Result<char> { fn peek(&mut self) -> Result<char> {
self.input.chars().next().ok_or(Error::Eof) self.input.chars().next().ok_or(DsnDeError::Eof)
} }
fn next(&mut self) -> Result<char> { fn next(&mut self) -> Result<char> {
let chr = self.peek()?; let chr = self.peek()?;
self.input = &self.input[1..]; self.input = &self.input[1..];
if chr == '\n' { if chr == '\n' {
self.line += 1; self.context.line += 1;
self.column = 0; self.context.column = 0;
} else { } else {
self.column += 1; self.context.column += 1;
} }
Ok(chr) Ok(chr)
} }
@ -111,9 +123,9 @@ impl<'de> Deserializer<'de> {
Ok(string) => match string.as_str() { Ok(string) => match string.as_str() {
"on" => Ok(true), "on" => Ok(true),
"off" => Ok(false), "off" => Ok(false),
_ => Err(Error::ExpectedBool), _ => Err(DsnDeError::ExpectedBool),
}, },
Err(_) => Err(Error::ExpectedBool), Err(_) => Err(DsnDeError::ExpectedBool),
} }
} }
@ -140,8 +152,7 @@ impl<'de> Deserializer<'de> {
if string.len() > 0 { if string.len() > 0 {
return Ok(string); return Ok(string);
} else { } else {
//dbg!(self.line, self.column); return Err(DsnDeError::ExpectedUnquoted);
return Err(Error::ExpectedUnquoted);
} }
} }
} }
@ -160,7 +171,7 @@ impl<'de> Deserializer<'de> {
// but there's no reason we shouldn't try to parse the file anyway, no ambiguity arises // but there's no reason we shouldn't try to parse the file anyway, no ambiguity arises
// maybe this should log a warning and proceed? // maybe this should log a warning and proceed?
if self.space_in_quoted_tokens != true && chr == ' ' { if self.space_in_quoted_tokens != true && chr == ' ' {
return Err(Error::SpaceInQuoted); return Err(DsnDeError::SpaceInQuoted);
} }
if Some(chr) == self.string_quote { if Some(chr) == self.string_quote {
@ -173,7 +184,7 @@ impl<'de> Deserializer<'de> {
} }
} }
pub fn from_str<'a, T>(input: &'a str) -> Result<T> /*pub fn from_str<'a, T>(input: &'a str) -> Result<T>
where where
T: Deserialize<'a>, T: Deserialize<'a>,
{ {
@ -184,10 +195,10 @@ where
dbg!(deserializer.input); dbg!(deserializer.input);
}*/ }*/
Ok(t) Ok(t)
} }*/
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
type Error = Error; type Error = DsnDeError;
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value> fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
where where
@ -359,17 +370,19 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>, V: Visitor<'de>,
{ {
if self.next()? != '(' { if self.next()? != '(' {
return Err(Error::ExpectedOpeningParen); return Err(DsnDeError::ExpectedOpeningParen);
} }
self.skip_ws(); self.skip_ws();
if &self.parse_identifier()? != name { let parsed_keyword = self.parse_identifier()?;
return Err(Error::ExpectedStruct(name));
if parsed_keyword != name {
return Err(DsnDeError::WrongKeyword(name, parsed_keyword));
} }
self.skip_ws(); self.skip_ws();
if self.next()? != ')' { if self.next()? != ')' {
return Err(Error::ExpectedClosingParen); return Err(DsnDeError::ExpectedClosingParen);
} }
self.skip_ws(); self.skip_ws();
@ -383,12 +396,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>, V: Visitor<'de>,
{ {
if self.next()? != '(' { if self.next()? != '(' {
return Err(Error::ExpectedOpeningParen); return Err(DsnDeError::ExpectedOpeningParen);
} }
self.skip_ws(); self.skip_ws();
if &self.parse_identifier()? != name { let parsed_keyword = self.parse_identifier()?;
return Err(Error::ExpectedStruct(name));
if parsed_keyword != name {
return Err(DsnDeError::WrongKeyword(name, parsed_keyword));
} }
self.skip_ws(); self.skip_ws();
@ -404,7 +419,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
let value = visitor.visit_seq(NewtypeStructFields::new(self))?; let value = visitor.visit_seq(NewtypeStructFields::new(self))?;
if self.next()? != ')' { if self.next()? != ')' {
return Err(Error::ExpectedClosingParen); return Err(DsnDeError::ExpectedClosingParen);
} }
self.skip_ws(); self.skip_ws();
@ -457,19 +472,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>, V: Visitor<'de>,
{ {
if self.next()? != '(' { if self.next()? != '(' {
return Err(Error::ExpectedOpeningParen); return Err(DsnDeError::ExpectedOpeningParen);
} }
self.skip_ws(); self.skip_ws();
if &self.parse_identifier()? != name { let parsed_keyword = self.parse_identifier()?;
return Err(Error::ExpectedStruct(name));
if parsed_keyword != name {
return Err(DsnDeError::WrongKeyword(name, parsed_keyword));
} }
self.skip_ws(); self.skip_ws();
let value = visitor.visit_seq(StructFields::new(self, fields))?; let value = visitor.visit_seq(StructFields::new(self, fields))?;
if self.next()? != ')' { if self.next()? != ')' {
return Err(Error::ExpectedClosingParen); return Err(DsnDeError::ExpectedClosingParen);
} }
self.skip_ws(); self.skip_ws();
@ -517,7 +534,7 @@ impl<'a, 'de> NewtypeStructFields<'a, 'de> {
} }
impl<'de, 'a> SeqAccess<'de> for NewtypeStructFields<'a, 'de> { impl<'de, 'a> SeqAccess<'de> for NewtypeStructFields<'a, 'de> {
type Error = Error; type Error = DsnDeError;
fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>> fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>>
where where
@ -542,7 +559,7 @@ impl<'a, 'de> ArrayIndices<'a, 'de> {
} }
impl<'de, 'a> SeqAccess<'de> for ArrayIndices<'a, 'de> { impl<'de, 'a> SeqAccess<'de> for ArrayIndices<'a, 'de> {
type Error = Error; type Error = DsnDeError;
fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>> fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>>
where where
@ -584,7 +601,7 @@ impl<'a, 'de> StructFields<'a, 'de> {
} }
impl<'de, 'a> SeqAccess<'de> for StructFields<'a, 'de> { impl<'de, 'a> SeqAccess<'de> for StructFields<'a, 'de> {
type Error = Error; type Error = DsnDeError;
fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>> fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>>
where where

View File

@ -1,4 +1,7 @@
use std::collections::HashMap; use std::{collections::HashMap, fmt};
use serde::Deserialize;
use thiserror::Error;
use crate::{ use crate::{
layout::{dot::FixedDotWeight, seg::FixedSegWeight, Layout}, layout::{dot::FixedDotWeight, seg::FixedSegWeight, Layout},
@ -6,11 +9,20 @@ use crate::{
}; };
use super::{ use super::{
de::{from_str, Error}, de::{Deserializer, DsnContext, DsnDeError},
rules::Rules, rules::Rules,
structure::Pcb, structure::Pcb,
}; };
#[derive(Error, Debug)]
pub struct DsnError(DsnContext, DsnDeError);
impl fmt::Display for DsnError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{0}: {1}", self.0, self.1)
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct DsnDesign { pub struct DsnDesign {
pcb: Pcb, pcb: Pcb,
@ -18,9 +30,12 @@ pub struct DsnDesign {
} }
impl DsnDesign { impl DsnDesign {
pub fn load_from_file(filename: &str) -> Result<Self, Error> { pub fn load_from_file(filename: &str) -> Result<Self, DsnError> {
let contents = std::fs::read_to_string(filename).unwrap(); // TODO: remove unwrap. let contents = std::fs::read_to_string(filename).unwrap(); // TODO: remove unwrap.
let pcb = from_str::<Pcb>(&contents)?; //let pcb = from_str::<Pcb>(&contents).map_err(|err| DsnError())?;
let mut deserializer = Deserializer::from_str(&contents);
let pcb = Pcb::deserialize(&mut deserializer)
.map_err(|err| DsnError(deserializer.context, err))?;
let rules = Rules::from_pcb(&pcb); let rules = Rules::from_pcb(&pcb);