mirror of https://codeberg.org/topola/topola.git
dsn: display line, column when printing error
This commit is contained in:
parent
7d0a17febd
commit
ec799fb107
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue