tgqe 0.0.2

The Great Qin Empire —— A centralized system for integrating and summarizing common compiler front-end library errors and span error output libraries, with optional Ariadne integration.
docs.rs failed to build tgqe-0.0.2
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

TGQE

中文(简体)

TOC

I. Description

TGQE is a Crate that makes it easy to integrate error handling from various compiler frontends, and comes with error conversions for multiple libraries and tunable configuration environment variables. When the number of errors exceeds a threshold, the remaining errors can be stored in SQLite to maintain a good reading experience. It uses Ariadne as the rendering implementation by default.

This project has no special relationship with the other projects mentioned in this document. tgqe is only a comprehensive integration library, it cannot help you write a good Lexer and Parser.


II. Usage

2.1 Quick Start

First, add tgqe to your project with the following command:

cargo add tgqe

Then enable the relevant features in your Cargo.toml. The currently available features are:

[features]



renderer      = ["ariadne", "dotenvy", "chrono"]



trans-chumsky = ["chumsky"]

trans-logos   = ["logos"]

trans-winnow  = ["winnow"]



store-to-db   = ["sqlx", "sqlx-sqlite", "chrono", "tokio", "dotenvy"]



chumsky-full = ["renderer", "trans-chumsky", "store-to-db"]

winnow-full  = ["renderer", "trans-winnow" , "store-to-db"]

logos-full   = ["renderer", "trans-logos"  , "store-to-db"]



all = ["chumsky-full", "winnow-full", "logos-full"]

Since most of logos's errors are compile-time errors, currently only logos::Span is converted.


2.2 Simple Example

Here is a simple example:

use tgqe::base_types::*;
use tgqe::enums::TgqeLevelFilter;
use tgqe::singletons::{ICC, SourceManager};

mod lexer; // Your Custom Lexer Implements

#[tokio::main(flavor = "current_thread")] // Only required if the `store-to-db` feature is enabled
async fn main() {
    if let Err(e) =
        TgqeReader::store_file(&path)
    {
        eprintln!("{}", e);
        std::process::exit(1);
    }
    let lines = SourceManager
        .lock()
        .unwrap()
        .iter_line()
        .filter(|line| {
            line.filepath == path
        });
    let mut lexer = lexer::Lexer::new();

    for line in lines {
        let (_, errors) =
            lexer.lex_line(&line.code);

        if !errors.is_empty() {
            let mut ctxs: Vec<TgqeCtx> =
                errors
                    .iter()
                    .map(|e| {
                        to_ctx(e, &path)
                    })
                    .collect();
            ICC.lock()
                .unwrap()
                .report(&mut ctxs) // Report the errors
                .await;
        }
    }
}


2.3 Integrate

You can also use it as an integration for your hand-written compiler frontend.

Sometimes what we need is not a specific error, but an object that "looks like an error and can express the information we need".

tgqe exposes the following main information structs:

pub struct TgqeCtx {
    pub position: TgqePosition,
    pub err_info: TgqeErrorInfo,
    pub hints: String,
    pub labels: String,
    pub publisher: String,
    pub ns_timestamp: i64,
}

pub struct TgqePosition {
    pub coord: TgqeCoordinate,
    pub span: TgqeSpan,
}

pub struct TgqeCoordinate {
    pub filepath: String,
    pub offset: u32,
    pub line: i16,
    pub column: i8,
}

pub struct TgqeSpan {
    pub start: TgqeCoordinate,
    pub end: TgqeCoordinate,
}

pub struct TgqeErrorInfo {
    pub err_type: String,
    pub expect: String,
    pub got: String,
    pub level: TgqeLevelFilter,
    pub recoverable: bool,
}

pub enum TgqeLevelFilter {
    Error,
    Warn,
    Info,
    Undefined,
}

As you can see, these are all plain structs rather than inscrutable generic gymnastics, so you can easily implement From for your own data structures.

For example, for chumsky::error::Rich:

use chumsky::error::Rich;

impl<T: core::fmt::Display> From<Rich<'_, T>>
    for TgqeCtx
{
    fn from(value: Rich<'_, T>) -> Self {
        let (expect, got) = match value
            .reason()
        {
            RichReason::ExpectedFound {
                expected,
                found,
            } => (
                expected
                    .iter()
                    .map(ToString::to_string)
                    .collect::<Vec<_>>()
                    .join(", "),
                found
                    .as_ref()
                    .map(|tok| {
                        tok.to_string()
                    })
                    .unwrap_or_else(|| {
                        "end of input"
                            .to_string()
                    }),
            ),
            RichReason::Custom(msg) => (
                TGQE_DEFAULT_STR.to_string(),
                msg.clone(),
            ),
        };

        let hints = value
            .contexts()
            .map(|(label, _)| {
                label.to_string()
            })
            .collect::<Vec<_>>()
            .join(", ");

        Self::new(
            unknown_position(
                value.span().start as u32,
            ),
            TgqeErrorInfo::new(
                TGQE_ERRTYPE_CHUMSKY_RICH,
                &expect,
                &got,
                TgqeLevelFilter::Error,
            ),
            &hints,
            TGQE_DEFAULT_STR,
            TGQE_PUBLISHER_CHUMSKY,
            0,
        )
    }
}

2.4 Example

You can check tgqe-golex-example for more information.


III. Output

The default renderer implementation of this project is based on Ariadne. It consumes the TgqeCtx objects and outputs error messages like the following:

output


IV. License

This project is open-sourced under the BSD-3 license.