rsjsonnet-front 0.5.0

A Jsonnet front end (source loading and error printing) library
Documentation
use rsjsonnet_lang::parser::{ActualToken, ExpectedToken, ParseError};
use rsjsonnet_lang::span::SpanManager;
use rsjsonnet_lang::token::STokenKind;

use super::TextPartKind;
use super::message::{LabelKind, Message, MessageKind, MessageLabel};
use crate::src_manager::SrcManager;

#[must_use]
pub(crate) fn render_error(
    error: &ParseError,
    span_mgr: &SpanManager,
    src_mgr: &SrcManager,
) -> Vec<(String, TextPartKind)> {
    let mut out = Vec::new();

    match *error {
        ParseError::Expected {
            span,
            ref expected,
            ref instead,
        } => {
            let mut expected_str = String::new();
            for (i, expected_thing) in expected.iter().enumerate() {
                if i != 0 {
                    if i == expected.len() - 1 {
                        expected_str.push_str(" or ");
                    } else {
                        expected_str.push_str(", ");
                    }
                }
                expected_str.push_str(&expected_to_string(*expected_thing));
            }
            Message {
                kind: MessageKind::Error,
                message: format!(
                    "expected {expected_str} instead of {}",
                    actual_to_string(instead),
                ),
                labels: vec![MessageLabel {
                    span,
                    kind: LabelKind::Error,
                    text: if *instead == ActualToken::EndOfFile {
                        "unexpected end-of-file".into()
                    } else {
                        "unexpected token".into()
                    },
                }],
            }
            .render(span_mgr, src_mgr, &mut out);
        }
    }

    out.push(('\n'.into(), TextPartKind::Space));
    out
}

fn expected_to_string(token: ExpectedToken) -> String {
    match token {
        ExpectedToken::EndOfFile => "end-of-file".into(),
        ExpectedToken::Simple(kind) => format!("`{}`", simple_token_to_str(kind)),
        ExpectedToken::Ident => "identifier".into(),
        ExpectedToken::Number => "number".into(),
        ExpectedToken::String => "string".into(),
        ExpectedToken::TextBlock => "text block".into(),
        ExpectedToken::Expr => "expression".into(),
        ExpectedToken::BinaryOp => "binary operator".into(),
    }
}

fn actual_to_string(token: &ActualToken) -> String {
    match token {
        ActualToken::EndOfFile => "end-of-file".into(),
        ActualToken::Simple(kind) => format!("`{}`", simple_token_to_str(*kind)),
        ActualToken::OtherOp(op) => format!("`{op}`"),
        ActualToken::Ident(_) => "identifier".into(),
        ActualToken::Number => "number".into(),
        ActualToken::String => "string".into(),
        ActualToken::TextBlock => "text block".into(),
    }
}

fn simple_token_to_str(kind: STokenKind) -> &'static str {
    match kind {
        STokenKind::Assert => "assert",
        STokenKind::Else => "else",
        STokenKind::Error => "error",
        STokenKind::False => "false",
        STokenKind::For => "for",
        STokenKind::Function => "function",
        STokenKind::If => "if",
        STokenKind::Import => "import",
        STokenKind::Importstr => "importstr",
        STokenKind::Importbin => "importbin",
        STokenKind::In => "in",
        STokenKind::Local => "local",
        STokenKind::Null => "null",
        STokenKind::Tailstrict => "tailstrict",
        STokenKind::Then => "then",
        STokenKind::Self_ => "self",
        STokenKind::Super => "super",
        STokenKind::True => "true",
        STokenKind::Exclam => "!",
        STokenKind::ExclamEq => "!=",
        STokenKind::Dollar => "$",
        STokenKind::Percent => "%",
        STokenKind::Amp => "&",
        STokenKind::AmpAmp => "&&",
        STokenKind::LeftParen => "(",
        STokenKind::RightParen => ")",
        STokenKind::Asterisk => "*",
        STokenKind::Plus => "+",
        STokenKind::PlusColon => "+:",
        STokenKind::PlusColonColon => "+::",
        STokenKind::PlusColonColonColon => "+:::",
        STokenKind::Comma => ",",
        STokenKind::Minus => "-",
        STokenKind::Dot => ".",
        STokenKind::Slash => "/",
        STokenKind::Colon => ":",
        STokenKind::ColonColon => "::",
        STokenKind::ColonColonColon => ":::",
        STokenKind::Semicolon => ";",
        STokenKind::Lt => "<",
        STokenKind::LtLt => "<<",
        STokenKind::LtEq => "<=",
        STokenKind::Eq => "=",
        STokenKind::EqEq => "==",
        STokenKind::Gt => ">",
        STokenKind::GtEq => ">=",
        STokenKind::GtGt => ">>",
        STokenKind::LeftBracket => "[",
        STokenKind::RightBracket => "]",
        STokenKind::Hat => "^",
        STokenKind::LeftBrace => "{",
        STokenKind::Pipe => "|",
        STokenKind::PipePipe => "||",
        STokenKind::RightBrace => "}",
        STokenKind::Tilde => "~",
    }
}