trixy 0.4.0

A rust crate used to generate multi-language apis for your application
Documentation
/*
* Copyright (C) 2023 - 2024:
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is part of the Trixy crate for Trinitrix.
*
* Trixy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/

use std::{error::Error, fmt::Display};
use thiserror::Error;

use crate::parser::{
    command_spec::unchecked::{Attribute, StringLiteral},
    error::{AdditionalHelp, ErrorContext, ErrorContextDisplay},
    lexing::{TokenKind, TokenSpan},
};

#[derive(Error, Debug, Clone)]
pub enum ParsingError {
    #[error("Expected '{expected}', but received: '{actual}'")]
    ExpectedDifferentToken {
        expected: TokenKind,
        actual: TokenKind,
        span: TokenSpan,
    },

    #[error("Expected '{expected}', but the token stream stopped")]
    UnexpectedEOF {
        expected: TokenKind,
        span: TokenSpan,
    },

    #[error("Expected a Keyword to start a new declaration, but found: '{actual}'")]
    ExpectedKeyword { actual: TokenKind, span: TokenSpan },

    #[error("Attribute does not have target")]
    TrailingAttribute {
        comments: Vec<Attribute>,
        span: TokenSpan,
    },

    #[error("Derive value is not known")]
    WrongDeriveValue { specified: StringLiteral },
}
impl ParsingError {
    pub fn span(&self) -> &TokenSpan {
        match self {
            ParsingError::ExpectedDifferentToken { span, .. } => span,
            ParsingError::ExpectedKeyword { span, .. } => span,
            ParsingError::TrailingAttribute { span, .. } => span,
            ParsingError::UnexpectedEOF { span, .. } => span,
            ParsingError::WrongDeriveValue { specified } => &specified.span,
        }
    }

    pub fn get_span(&self) -> TokenSpan {
        *self.span()
    }
}

impl AdditionalHelp for ParsingError {
    fn additional_help(&self) -> String {
        match self {
            ParsingError::ExpectedDifferentToken {
                expected,
                actual,
                ..
            } => format!(
                "I expected a '{}' here, but you put a '{}' there!",
                expected, actual
            ),
            ParsingError::ExpectedKeyword { actual, .. } => format!(
            "I expected a keyword (that is something like 'fn' or 'mod') but you put a '{}' there!",
            actual),
            ParsingError::TrailingAttribute { .. } => "I expected some target (a function, namespace, enum, or something like this) which this attribute annotates, but you put nothing there".to_owned(),
            ParsingError::UnexpectedEOF { expected, .. } => format!("Put the expected token ('{expected}') here."),
            ParsingError::WrongDeriveValue { specified } => format!("'{}' is not a valid derive value! Take a look a the grammar file", specified.content),
        }
    }
}

#[derive(Debug, Clone)]
pub struct SpannedParsingError {
    pub source: Box<ParsingError>,
    pub context: ErrorContext,
}

impl Error for SpannedParsingError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        Some(&self.source)
    }
}

impl Display for SpannedParsingError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.error_fmt(f)
    }
}

impl ErrorContextDisplay for SpannedParsingError {
    type Error = ParsingError;

    fn context(&self) -> &crate::parser::error::ErrorContext {
        &self.context
    }

    fn line_number(&self) -> usize {
        self.context.line_number
    }

    fn line_above(&self) -> &str {
        &self.context.line_above
    }

    fn line_below(&self) -> &str {
        &self.context.line_below
    }

    fn line(&self) -> &str {
        &self.context.line
    }

    fn source(&self) -> &<SpannedParsingError as ErrorContextDisplay>::Error {
        &self.source
    }
}