From 4bcaf945d739fec76f2ba6ad6718f78af713c351 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Sat, 4 May 2024 22:35:18 +0200 Subject: [PATCH] lang: add highlighting to errors --- Cargo.lock | 37 ++++++++++++ crates/lang/Cargo.toml | 1 + crates/lang/src/lst_parser/input.rs | 15 ++++- crates/lang/src/lst_parser/output.rs | 86 ++++++++++++++++++++++++---- crates/lang/src/main.rs | 2 +- testfiles/test.owo | 2 +- 6 files changed, 128 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0252665..cc9818c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -469,6 +469,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "ident_case" version = "1.0.1" @@ -519,6 +525,23 @@ dependencies = [ "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]] name = "itoa" version = "1.0.10" @@ -546,6 +569,7 @@ dependencies = [ "indexmap", "indoc", "logos", + "owo-colors", "petgraph", "rowan", ] @@ -697,6 +721,9 @@ name = "owo-colors" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" +dependencies = [ + "supports-color", +] [[package]] name = "petgraph" @@ -974,6 +1001,16 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "svg-filters" version = "0.1.0" diff --git a/crates/lang/Cargo.toml b/crates/lang/Cargo.toml index c64720c..8a9c80b 100644 --- a/crates/lang/Cargo.toml +++ b/crates/lang/Cargo.toml @@ -16,6 +16,7 @@ rowan = "0.15.15" drop_bomb = "0.1.5" enumset = "1.1.3" indoc = "2" +owo-colors = {version = "4", features = ["supports-colors"]} [lints] workspace = true diff --git a/crates/lang/src/lst_parser/input.rs b/crates/lang/src/lst_parser/input.rs index e9a5e2e..a00d862 100644 --- a/crates/lang/src/lst_parser/input.rs +++ b/crates/lang/src/lst_parser/input.rs @@ -1,5 +1,9 @@ +use enumset::enum_set; + use crate::lst_parser::syntax_kind::SyntaxKind; +use super::syntax_kind::TokenSet; + pub struct Input<'src, 'toks> { raw: &'toks Vec<(SyntaxKind, &'src str)>, /// indices of the "meaningful" tokens (not whitespace etc) @@ -10,14 +14,19 @@ pub struct Input<'src, 'toks> { newlines: Vec, } +pub const MEANINGLESS_TOKS: TokenSet = enum_set!(SyntaxKind::WHITESPACE | SyntaxKind::NEWLINE); + impl<'src, 'toks> Input<'src, 'toks> { pub fn new(raw_toks: &'toks Vec<(SyntaxKind, &'src str)>) -> Self { let meaningful = raw_toks .iter() .enumerate() - .filter_map(|(i, tok)| match tok.0 { - SyntaxKind::WHITESPACE | SyntaxKind::NEWLINE => None, - _ => Some(i), + .filter_map(|(i, tok)| { + if MEANINGLESS_TOKS.contains(tok.0) { + None + } else { + Some(i) + } }) .collect(); let newlines = raw_toks diff --git a/crates/lang/src/lst_parser/output.rs b/crates/lang/src/lst_parser/output.rs index 141d7d9..f17d97e 100644 --- a/crates/lang/src/lst_parser/output.rs +++ b/crates/lang/src/lst_parser/output.rs @@ -1,7 +1,11 @@ +use owo_colors::{unset_override, OwoColorize}; use rowan::{GreenNode, GreenNodeBuilder, GreenNodeData, GreenTokenData, Language, NodeOrToken}; 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}; @@ -14,47 +18,109 @@ impl std::fmt::Debug for Output { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut errs: Vec<&SyntaxError> = self.errors.iter().collect(); 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( node: NodeOrToken<&GreenNodeData, &GreenTokenData>, - f: &mut std::fmt::Formatter<'_>, + f: &mut dyn std::fmt::Write, lvl: i32, errs: &mut Vec<&SyntaxError>, + colored: bool, ) -> std::fmt::Result { for _ in 0..lvl { 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) => { let kind = Lang::kind_from_raw(node.kind()); 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 { let err = errs .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() { - debug_print_green_node(c, f, lvl + 1, errs)?; + debug_print_green_node(c, f, lvl + 1, errs, colored)?; } for _ in 0..lvl { 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) => { - 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 { + 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( mut raw_toks: Vec<(SyntaxKind, &str)>, (mut events, errs): (Vec, Vec), diff --git a/crates/lang/src/main.rs b/crates/lang/src/main.rs index 517094d..2531709 100644 --- a/crates/lang/src/main.rs +++ b/crates/lang/src/main.rs @@ -23,7 +23,7 @@ fn main() { let p_out = dbg!(parser.finish()); let o = Output::from_parser_output(toks, p_out); - println!("Out: {:?}", o); + println!("{}", o.debug_colored()); // let parse_res = parser::parse(&f); // println!("parse: {:?}", parse_res); diff --git a/testfiles/test.owo b/testfiles/test.owo index bbcf720..ac1af18 100644 --- a/testfiles/test.owo +++ b/testfiles/test.owo @@ -1 +1 @@ -meow 1 (3 | add 1) +meow | gay |