lang: add highlighting to errors

This commit is contained in:
Schrottkatze 2024-05-04 22:35:18 +02:00
parent 29cdcfbe0c
commit 4bcaf945d7
No known key found for this signature in database
6 changed files with 128 additions and 15 deletions

37
Cargo.lock generated
View file

@ -469,6 +469,12 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" version = "1.0.1"
@ -519,6 +525,23 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "is-terminal"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "is_ci"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.10" version = "1.0.10"
@ -546,6 +569,7 @@ dependencies = [
"indexmap", "indexmap",
"indoc", "indoc",
"logos", "logos",
"owo-colors",
"petgraph", "petgraph",
"rowan", "rowan",
] ]
@ -697,6 +721,9 @@ name = "owo-colors"
version = "4.0.0" version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
dependencies = [
"supports-color",
]
[[package]] [[package]]
name = "petgraph" name = "petgraph"
@ -974,6 +1001,16 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "supports-color"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89"
dependencies = [
"is-terminal",
"is_ci",
]
[[package]] [[package]]
name = "svg-filters" name = "svg-filters"
version = "0.1.0" version = "0.1.0"

View file

@ -16,6 +16,7 @@ rowan = "0.15.15"
drop_bomb = "0.1.5" drop_bomb = "0.1.5"
enumset = "1.1.3" enumset = "1.1.3"
indoc = "2" indoc = "2"
owo-colors = {version = "4", features = ["supports-colors"]}
[lints] [lints]
workspace = true workspace = true

View file

@ -1,5 +1,9 @@
use enumset::enum_set;
use crate::lst_parser::syntax_kind::SyntaxKind; use crate::lst_parser::syntax_kind::SyntaxKind;
use super::syntax_kind::TokenSet;
pub struct Input<'src, 'toks> { pub struct Input<'src, 'toks> {
raw: &'toks Vec<(SyntaxKind, &'src str)>, raw: &'toks Vec<(SyntaxKind, &'src str)>,
/// indices of the "meaningful" tokens (not whitespace etc) /// indices of the "meaningful" tokens (not whitespace etc)
@ -10,14 +14,19 @@ pub struct Input<'src, 'toks> {
newlines: Vec<usize>, newlines: Vec<usize>,
} }
pub const MEANINGLESS_TOKS: TokenSet = enum_set!(SyntaxKind::WHITESPACE | SyntaxKind::NEWLINE);
impl<'src, 'toks> Input<'src, 'toks> { impl<'src, 'toks> Input<'src, 'toks> {
pub fn new(raw_toks: &'toks Vec<(SyntaxKind, &'src str)>) -> Self { pub fn new(raw_toks: &'toks Vec<(SyntaxKind, &'src str)>) -> Self {
let meaningful = raw_toks let meaningful = raw_toks
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(i, tok)| match tok.0 { .filter_map(|(i, tok)| {
SyntaxKind::WHITESPACE | SyntaxKind::NEWLINE => None, if MEANINGLESS_TOKS.contains(tok.0) {
_ => Some(i), None
} else {
Some(i)
}
}) })
.collect(); .collect();
let newlines = raw_toks let newlines = raw_toks

View file

@ -1,7 +1,11 @@
use owo_colors::{unset_override, OwoColorize};
use rowan::{GreenNode, GreenNodeBuilder, GreenNodeData, GreenTokenData, Language, NodeOrToken}; use rowan::{GreenNode, GreenNodeBuilder, GreenNodeData, GreenTokenData, Language, NodeOrToken};
use std::mem; use std::mem;
use crate::lst_parser::syntax_kind::{Lang, SyntaxKind}; use crate::lst_parser::{
input::MEANINGLESS_TOKS,
syntax_kind::{Lang, SyntaxKind},
};
use super::{error::SyntaxError, events::Event}; use super::{error::SyntaxError, events::Event};
@ -14,47 +18,109 @@ impl std::fmt::Debug for Output {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut errs: Vec<&SyntaxError> = self.errors.iter().collect(); let mut errs: Vec<&SyntaxError> = self.errors.iter().collect();
errs.reverse(); errs.reverse();
debug_print_green_node(NodeOrToken::Node(&self.green_node), f, 0, &mut errs)
debug_print_green_node(NodeOrToken::Node(&self.green_node), f, 0, &mut errs, false)
} }
} }
fn debug_print_green_node( fn debug_print_green_node(
node: NodeOrToken<&GreenNodeData, &GreenTokenData>, node: NodeOrToken<&GreenNodeData, &GreenTokenData>,
f: &mut std::fmt::Formatter<'_>, f: &mut dyn std::fmt::Write,
lvl: i32, lvl: i32,
errs: &mut Vec<&SyntaxError>, errs: &mut Vec<&SyntaxError>,
colored: bool,
) -> std::fmt::Result { ) -> std::fmt::Result {
for _ in 0..lvl { for _ in 0..lvl {
f.write_str(" ")?; f.write_str(" ")?;
} }
match node { if !colored {
owo_colors::set_override(false);
} else {
owo_colors::set_override(true);
}
let r = match node {
NodeOrToken::Node(n) => { NodeOrToken::Node(n) => {
let kind = Lang::kind_from_raw(node.kind()); let kind = Lang::kind_from_raw(node.kind());
if kind != SyntaxKind::PARSE_ERR { if kind != SyntaxKind::PARSE_ERR {
writeln!(f, "{:?} {{", Lang::kind_from_raw(node.kind()))?; writeln!(
f,
"{:?} {}",
Lang::kind_from_raw(node.kind()).bright_yellow().bold(),
"{".yellow()
)?;
} else { } else {
let err = errs let err = errs
.pop() .pop()
.expect("all error syntax nodes should correspond to an error"); .expect("all error syntax nodes should correspond to an error")
.bright_red();
writeln!(f, "{:?}: {err:?} {{", kind)?; writeln!(
f,
"{:?}{} {err:?} {}",
kind.bright_red().bold(),
":".red(),
"{".bright_red().bold()
)?;
} }
for c in n.children() { for c in n.children() {
debug_print_green_node(c, f, lvl + 1, errs)?; debug_print_green_node(c, f, lvl + 1, errs, colored)?;
} }
for _ in 0..lvl { for _ in 0..lvl {
f.write_str(" ")?; f.write_str(" ")?;
} }
f.write_str("}\n") if kind != SyntaxKind::PARSE_ERR {
write!(f, "{}", "}\n".yellow())
} else {
write!(f, "{}", "}\n".bright_red().bold())
}
} }
NodeOrToken::Token(t) => { NodeOrToken::Token(t) => {
writeln!(f, "{:?} {:?};", Lang::kind_from_raw(t.kind()), t.text()) let tok = Lang::kind_from_raw(t.kind());
if MEANINGLESS_TOKS.contains(tok) {
writeln!(
f,
"{:?} {:?}{}",
Lang::kind_from_raw(t.kind()).white(),
t.text().white(),
";".white()
)
} else {
writeln!(
f,
"{:?} {:?}{}",
Lang::kind_from_raw(t.kind()).bright_cyan().bold(),
t.text().green(),
";".yellow()
)
} }
} }
};
if !colored {
owo_colors::unset_override();
}
r
} }
impl Output { impl Output {
pub fn debug_colored(&self) -> String {
let mut out = String::new();
let mut errs: Vec<&SyntaxError> = self.errors.iter().collect();
errs.reverse();
let _ = debug_print_green_node(
NodeOrToken::Node(&self.green_node),
&mut out,
0,
&mut errs,
true,
);
out
}
pub fn from_parser_output( pub fn from_parser_output(
mut raw_toks: Vec<(SyntaxKind, &str)>, mut raw_toks: Vec<(SyntaxKind, &str)>,
(mut events, errs): (Vec<Event>, Vec<SyntaxError>), (mut events, errs): (Vec<Event>, Vec<SyntaxError>),

View file

@ -23,7 +23,7 @@ fn main() {
let p_out = dbg!(parser.finish()); let p_out = dbg!(parser.finish());
let o = Output::from_parser_output(toks, p_out); let o = Output::from_parser_output(toks, p_out);
println!("Out: {:?}", o); println!("{}", o.debug_colored());
// let parse_res = parser::parse(&f); // let parse_res = parser::parse(&f);
// println!("parse: {:?}", parse_res); // println!("parse: {:?}", parse_res);

View file

@ -1 +1 @@
meow 1 (3 | add 1) meow | gay |