add custom error type
This commit is contained in:
parent
73580c4ff0
commit
e1f64548b4
|
@ -4,6 +4,7 @@ mod package;
|
|||
mod parser;
|
||||
mod rtlil;
|
||||
|
||||
use ariadne::Source;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
@ -48,11 +49,9 @@ fn main() {
|
|||
if opt.debug {
|
||||
println!("{err:#?}");
|
||||
}
|
||||
/*
|
||||
parser::error::convert_error(input, err)
|
||||
.eprint(Source::from(input.fragment()))
|
||||
.unwrap();
|
||||
*/
|
||||
}
|
||||
Err(_) => (unreachable!()),
|
||||
Ok(res) => {
|
||||
|
|
|
@ -1,23 +1,124 @@
|
|||
use super::tokens::{TokenKind, TokenSpan};
|
||||
use super::{IErr, Span};
|
||||
use ariadne::{Label, Report, ReportKind};
|
||||
use nom_greedyerror::{GreedyErrorKind, Position};
|
||||
use nom::error::{ContextError, ParseError};
|
||||
use nom::InputTake;
|
||||
|
||||
fn span_to_range(input: Span) -> std::ops::Range<usize> {
|
||||
input.position()..(input.position() + input.len())
|
||||
#[derive(Debug)]
|
||||
pub struct Error<I> {
|
||||
pub errors: Vec<(I, ErrorKind)>,
|
||||
}
|
||||
|
||||
pub fn convert_error(_input: Span, e: IErr<Span>) -> Report {
|
||||
let mut labels = Vec::new();
|
||||
for err in e.errors {
|
||||
let label = match err.1 {
|
||||
GreedyErrorKind::Context(ctx) => {
|
||||
Label::new(span_to_range(err.0)).with_message(format!("in {ctx}"))
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ErrorKind {
|
||||
/// A static context string
|
||||
Context(&'static str),
|
||||
/// An expected character
|
||||
Char(char),
|
||||
/// An expected token
|
||||
Token(TokenKind),
|
||||
/// A list of valid tokens
|
||||
Tokens(Vec<TokenKind>),
|
||||
/// A nom error
|
||||
Nom(nom::error::ErrorKind),
|
||||
}
|
||||
|
||||
impl<I> ParseError<I> for Error<I>
|
||||
where
|
||||
I: InputPos + std::fmt::Debug + Clone,
|
||||
{
|
||||
fn from_error_kind(input: I, kind: nom::error::ErrorKind) -> Self {
|
||||
Self {
|
||||
errors: vec![(input, ErrorKind::Nom(kind))],
|
||||
}
|
||||
}
|
||||
|
||||
fn append(input: I, kind: nom::error::ErrorKind, mut other: Self) -> Self {
|
||||
other.errors.push((input, ErrorKind::Nom(kind)));
|
||||
other
|
||||
}
|
||||
|
||||
fn from_char(input: I, c: char) -> Self {
|
||||
Self {
|
||||
errors: vec![(input, ErrorKind::Char(c))],
|
||||
}
|
||||
}
|
||||
|
||||
fn or(mut self, mut other: Self) -> Self {
|
||||
let self_first = self.errors.first();
|
||||
let other_first = other.errors.first();
|
||||
match (self_first, other_first) {
|
||||
(Some((is, ErrorKind::Token(s))), Some((io, ErrorKind::Token(o)))) => {
|
||||
let combined_kind = ErrorKind::Tokens(vec![s.clone(), o.clone()]);
|
||||
other.errors[0] = (io.clone(), combined_kind);
|
||||
other
|
||||
}
|
||||
_ => {
|
||||
other.errors.extend_from_slice(&self.errors[..]);
|
||||
other
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ContextError<I> for Error<I> {
|
||||
fn add_context(input: I, ctx: &'static str, mut other: Self) -> Self {
|
||||
other.errors.push((input, ErrorKind::Context(ctx)));
|
||||
other
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Error<I> {
|
||||
pub fn from_tokenkind(input: I, kind: TokenKind) -> Self {
|
||||
Self {
|
||||
errors: vec![(input, ErrorKind::Token(kind))],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InputPos {
|
||||
fn position(&self) -> usize;
|
||||
}
|
||||
|
||||
impl InputPos for Span<'_> {
|
||||
fn position(&self) -> usize {
|
||||
self.location_offset()
|
||||
}
|
||||
}
|
||||
|
||||
fn tokspan_to_range(input: TokenSpan) -> std::ops::Range<usize> {
|
||||
let first = input.first().unwrap().span().position();
|
||||
let last_span = input.last().unwrap().span();
|
||||
let last = last_span.position() + last_span.len();
|
||||
first..last
|
||||
}
|
||||
|
||||
fn label_tokspan(input: TokenSpan) -> Label {
|
||||
Label::new(tokspan_to_range(input))
|
||||
}
|
||||
|
||||
pub fn convert_error(_input: Span, e: IErr<TokenSpan>) -> Report {
|
||||
let mut labels = Vec::new();
|
||||
let mut colors = ariadne::ColorGenerator::new();
|
||||
for (input, err) in e.errors {
|
||||
let label = match err {
|
||||
ErrorKind::Context(ctx) => label_tokspan(input).with_message(format!("in {ctx}")),
|
||||
ErrorKind::Char(c) => label_tokspan(input).with_message(format!("expected {c:?}")),
|
||||
ErrorKind::Nom(kind) => {
|
||||
label_tokspan(input).with_message(format!("nom error {kind:?}"))
|
||||
}
|
||||
ErrorKind::Token(t) => {
|
||||
let next = input.first().unwrap().kind();
|
||||
let msg = format!("expected {t:?} found {next:?}");
|
||||
label_tokspan(input.take(1)).with_message(msg)
|
||||
}
|
||||
ErrorKind::Tokens(ts) => {
|
||||
let next = input.first().unwrap().kind();
|
||||
let msg = format!("expected one of {ts:?} found {next:?}");
|
||||
label_tokspan(input.take(1)).with_message(msg)
|
||||
}
|
||||
GreedyErrorKind::Char(c) => Label::new(err.0.position()..err.0.position())
|
||||
.with_message(format!("expected {c:?}")),
|
||||
GreedyErrorKind::Nom(kind) => Label::new(err.0.position()..err.0.position())
|
||||
.with_message(format!("nom error {kind:?}")),
|
||||
};
|
||||
let label = label.with_color(colors.next());
|
||||
labels.push(label);
|
||||
}
|
||||
let mut rep = Report::build(ReportKind::Error, (), 0).with_message("Parse Error");
|
||||
|
|
|
@ -15,13 +15,12 @@ use nom::{
|
|||
multi::{many0, separated_list0},
|
||||
sequence::{delimited, pair, preceded, separated_pair, tuple},
|
||||
};
|
||||
use nom_greedyerror::GreedyError;
|
||||
use nom_locate::LocatedSpan;
|
||||
|
||||
// custom span type for nom_locate
|
||||
pub type Span<'a> = LocatedSpan<&'a str>;
|
||||
|
||||
pub type IErr<I> = GreedyError<I, ErrorKind>;
|
||||
pub type IErr<I> = error::Error<I>;
|
||||
// custom IResult type for VerboseError
|
||||
pub type IResult<I, O, E = IErr<I>> = nom::IResult<I, O, E>;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use nom::{
|
||||
branch::alt,
|
||||
combinator::map,
|
||||
combinator::{cut, map},
|
||||
error::context,
|
||||
multi::{many0, separated_list0},
|
||||
sequence::{delimited, preceded, tuple},
|
||||
|
@ -52,7 +52,11 @@ fn inputs_list(input: TokenSpan) -> IResult<TokenSpan, Vec<PortDecl>> {
|
|||
fn assign_item(input: TokenSpan) -> IResult<TokenSpan, Assign> {
|
||||
context(
|
||||
"assignment",
|
||||
delimited(token(tk::Assign), assign_statement, token(tk::Semicolon)),
|
||||
delimited(
|
||||
token(tk::Assign),
|
||||
cut(assign_statement),
|
||||
cut(token(tk::Semicolon)),
|
||||
),
|
||||
)(input)
|
||||
}
|
||||
|
||||
|
@ -64,23 +68,22 @@ fn module_item(input: TokenSpan) -> IResult<TokenSpan, ModuleItem> {
|
|||
}
|
||||
|
||||
pub fn module(input: TokenSpan) -> IResult<TokenSpan, Module> {
|
||||
context(
|
||||
"module",
|
||||
map(
|
||||
tuple((
|
||||
preceded(
|
||||
token(tk::Module),
|
||||
cut(tuple((
|
||||
token(tk::Ident),
|
||||
delimited(token(tk::LParen), inputs_list, token(tk::RParen)),
|
||||
preceded(token(tk::RArrow), typename),
|
||||
delimited(token(tk::LBrace), many0(module_item), token(tk::RBrace)),
|
||||
)),
|
||||
|(_, name, inputs, _ret, items)| Module {
|
||||
))),
|
||||
),
|
||||
|(name, inputs, _ret, items)| Module {
|
||||
// TODO: bring back returns
|
||||
name: name.span(),
|
||||
ports: inputs,
|
||||
items,
|
||||
},
|
||||
),
|
||||
)(input)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! convert text into a token stream
|
||||
|
||||
use super::{
|
||||
error::{Error, InputPos},
|
||||
literals::{identifier, ws0},
|
||||
IResult, Span,
|
||||
};
|
||||
|
@ -9,7 +10,6 @@ use nom::{
|
|||
bytes::complete::tag,
|
||||
character::complete::{anychar, digit1},
|
||||
combinator::{consumed, map, recognize},
|
||||
error::ParseError,
|
||||
multi::many0,
|
||||
};
|
||||
use std::fmt;
|
||||
|
@ -40,9 +40,12 @@ impl<'a> Token<'a> {
|
|||
pub fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
pub fn kind(&self) -> TokenKind {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum TokenKind {
|
||||
// no whitespace, for now
|
||||
// no token trees either, for now
|
||||
|
@ -92,6 +95,12 @@ impl<'a> TokenSpan<'a> {
|
|||
pub fn with_pos(rest: &'a [Token<'a>], pos: usize) -> Self {
|
||||
Self { rest, pos }
|
||||
}
|
||||
pub fn first(&self) -> Option<&Token> {
|
||||
self.rest.first()
|
||||
}
|
||||
pub fn last(&self) -> Option<&Token> {
|
||||
self.rest.last()
|
||||
}
|
||||
}
|
||||
|
||||
impl nom::InputTake for TokenSpan<'_> {
|
||||
|
@ -114,30 +123,22 @@ impl nom::InputLength for TokenSpan<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl nom_greedyerror::Position for TokenSpan<'_> {
|
||||
impl InputPos for TokenSpan<'_> {
|
||||
fn position(&self) -> usize {
|
||||
self.pos
|
||||
}
|
||||
}
|
||||
|
||||
/// combinator that matches a token kind
|
||||
pub fn token<'a, E>(
|
||||
kind: TokenKind,
|
||||
) -> impl FnMut(TokenSpan<'a>) -> nom::IResult<TokenSpan, &Token, E>
|
||||
where
|
||||
E: ParseError<TokenSpan<'a>>,
|
||||
{
|
||||
pub fn token<'a>(kind: TokenKind) -> impl FnMut(TokenSpan<'a>) -> IResult<TokenSpan, &Token> {
|
||||
move |input: TokenSpan| {
|
||||
let next = &input.rest[0];
|
||||
if next.kind == kind.clone() {
|
||||
let kind = kind.clone();
|
||||
if next.kind == kind {
|
||||
let rest = TokenSpan::with_pos(&input.rest[1..], input.pos + 1);
|
||||
Ok((rest, next))
|
||||
} else {
|
||||
Err(nom::Err::Error(E::from_error_kind(
|
||||
input,
|
||||
// TODO: Proper errors here
|
||||
nom::error::ErrorKind::Tag,
|
||||
)))
|
||||
Err(nom::Err::Error(Error::from_tokenkind(input, kind)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue