add error reporting stuffs
This commit is contained in:
parent
970ae0e449
commit
2d007c977c
6 changed files with 223 additions and 22 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -171,6 +171,16 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codespan-reporting"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||||
|
dependencies = [
|
||||||
|
"termcolor",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -1112,6 +1122,12 @@ version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1145,6 +1161,7 @@ name = "webthing"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"codespan-reporting",
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"font-kit",
|
"font-kit",
|
||||||
|
|
|
@ -14,3 +14,4 @@ font-kit = { version = "0.11", features = [ "loader-freetype" ]}
|
||||||
simple_logger = "4.3.3"
|
simple_logger = "4.3.3"
|
||||||
logos = "0.13.0"
|
logos = "0.13.0"
|
||||||
cosmic-text = "0.10.0"
|
cosmic-text = "0.10.0"
|
||||||
|
codespan-reporting = "0.11.1"
|
||||||
|
|
|
@ -15,3 +15,4 @@ more text
|
||||||
(heading level=2 "heading level 2 too")
|
(heading level=2 "heading level 2 too")
|
||||||
|
|
||||||
(heading level=3 "heading level 3 too")
|
(heading level=3 "heading level 3 too")
|
||||||
|
|
||||||
|
|
159
src/error.rs
Normal file
159
src/error.rs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
use std::{collections::HashMap, ops::Range, process};
|
||||||
|
|
||||||
|
use codespan_reporting::{
|
||||||
|
diagnostic::{Diagnostic, Label, Severity},
|
||||||
|
files::SimpleFiles,
|
||||||
|
term::{
|
||||||
|
self,
|
||||||
|
termcolor::{ColorChoice, StandardStream},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type Span = Range<usize>;
|
||||||
|
|
||||||
|
type FileId = usize;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||||
|
pub struct FileIdent<'a> {
|
||||||
|
id: FileId,
|
||||||
|
name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum DiagnosticKind {
|
||||||
|
InvalidToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum DiagCriticality {
|
||||||
|
/// Bugs in this program, unreachable code being reached, etc.
|
||||||
|
Bug,
|
||||||
|
|
||||||
|
// TODO: Better names
|
||||||
|
/// Critical errors that cannot be recovered from, prompt immediate exit
|
||||||
|
CriticalImmediate,
|
||||||
|
/// Critical, this program must exit after this processing step, but can continue and may find other diagnostics
|
||||||
|
CriticalFinishStep,
|
||||||
|
|
||||||
|
/// A warning, about to be deprecated syntax etc.
|
||||||
|
Warn,
|
||||||
|
|
||||||
|
/// Information/advice
|
||||||
|
Info,
|
||||||
|
Help,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagCriticality {
|
||||||
|
fn mk_diag_base(&self) -> Diagnostic<FileId> {
|
||||||
|
Diagnostic::new(match self {
|
||||||
|
DiagCriticality::Bug => Severity::Bug,
|
||||||
|
DiagCriticality::CriticalImmediate => Severity::Error,
|
||||||
|
DiagCriticality::CriticalFinishStep => Severity::Error,
|
||||||
|
DiagCriticality::Warn => Severity::Warning,
|
||||||
|
DiagCriticality::Info => Severity::Note,
|
||||||
|
DiagCriticality::Help => Severity::Help,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticKind {
|
||||||
|
pub fn criticality(&self) -> DiagCriticality {
|
||||||
|
match self {
|
||||||
|
DiagnosticKind::InvalidToken => DiagCriticality::CriticalFinishStep,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_diag(self, locs: &[Span], file_id: &FileIdent) -> Diagnostic<FileId> {
|
||||||
|
self.criticality()
|
||||||
|
.mk_diag_base()
|
||||||
|
.with_labels(
|
||||||
|
locs.iter()
|
||||||
|
.map(|span| Label::primary(file_id.id, span.clone()))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.with_message(match self {
|
||||||
|
DiagnosticKind::InvalidToken => {
|
||||||
|
if locs.len() > 1 {
|
||||||
|
"invalid tokens"
|
||||||
|
} else {
|
||||||
|
"invalid token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DiagnosticReporter<'a> {
|
||||||
|
files: SimpleFiles<&'a str, &'a str>,
|
||||||
|
errs: HashMap<FileIdent<'a>, HashMap<DiagnosticKind, Vec<Span>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DiagnosticReporter<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
files: SimpleFiles::new(),
|
||||||
|
errs: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_file(&mut self, name: &'a str, content: &'a str) -> FileIdent<'a> {
|
||||||
|
FileIdent {
|
||||||
|
id: self.files.add(name, content),
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_diagnostic(&mut self, file_id: FileIdent<'a>, loc: Span, kind: DiagnosticKind) {
|
||||||
|
self.errs
|
||||||
|
.entry(file_id)
|
||||||
|
.or_insert_with(|| HashMap::with_capacity(1));
|
||||||
|
|
||||||
|
if !self.errs[&file_id].contains_key(&kind) {
|
||||||
|
self.errs.get_mut(&file_id).unwrap().insert(kind, vec![loc]);
|
||||||
|
} else {
|
||||||
|
self.errs
|
||||||
|
.get_mut(&file_id)
|
||||||
|
.unwrap()
|
||||||
|
.get_mut(&kind)
|
||||||
|
.unwrap()
|
||||||
|
.push(loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
match kind.criticality() {
|
||||||
|
DiagCriticality::Bug | DiagCriticality::CriticalImmediate => self.finish_and_exit(),
|
||||||
|
DiagCriticality::CriticalFinishStep
|
||||||
|
| DiagCriticality::Warn
|
||||||
|
| DiagCriticality::Info
|
||||||
|
| DiagCriticality::Help => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fail_step_if_failed(&self) {
|
||||||
|
for (_, diags) in self.errs.iter() {
|
||||||
|
for kind in diags.keys() {
|
||||||
|
if matches!(
|
||||||
|
kind.criticality(),
|
||||||
|
DiagCriticality::Bug
|
||||||
|
| DiagCriticality::CriticalImmediate
|
||||||
|
| DiagCriticality::CriticalFinishStep
|
||||||
|
) {
|
||||||
|
self.finish_and_exit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_and_exit(&self) -> ! {
|
||||||
|
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||||
|
let config = term::Config::default();
|
||||||
|
|
||||||
|
for (file_id, diags) in self.errs.iter() {
|
||||||
|
for (kind, locs) in diags {
|
||||||
|
let writer = &mut writer.lock();
|
||||||
|
term::emit(writer, &config, &self.files, &kind.into_diag(locs, file_id))
|
||||||
|
.expect("can't even report errors :c");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
15
src/main.rs
15
src/main.rs
|
@ -11,6 +11,9 @@ use parse::parse_the_shit_out_of_this_but_manually;
|
||||||
|
|
||||||
use render::render_text;
|
use render::render_text;
|
||||||
|
|
||||||
|
use crate::error::DiagnosticReporter;
|
||||||
|
|
||||||
|
mod error;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod render;
|
mod render;
|
||||||
|
|
||||||
|
@ -34,9 +37,17 @@ fn main() {
|
||||||
args.x, args.y
|
args.x, args.y
|
||||||
);
|
);
|
||||||
|
|
||||||
let txt = fs::read_to_string(args.file).unwrap();
|
let mut reporter = DiagnosticReporter::new();
|
||||||
|
|
||||||
dbg!(parse_the_shit_out_of_this_but_manually(&txt));
|
let txt = fs::read_to_string(args.file.clone()).unwrap();
|
||||||
|
|
||||||
|
let fid = reporter.register_file(args.file.file_name().unwrap().to_str().unwrap(), &txt);
|
||||||
|
|
||||||
|
dbg!(parse_the_shit_out_of_this_but_manually(
|
||||||
|
&txt,
|
||||||
|
&mut reporter,
|
||||||
|
&fid
|
||||||
|
));
|
||||||
|
|
||||||
let mut dt = DrawTarget::new(args.x.into(), args.y.into());
|
let mut dt = DrawTarget::new(args.x.into(), args.y.into());
|
||||||
|
|
||||||
|
|
52
src/parse.rs
52
src/parse.rs
|
@ -2,9 +2,11 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use logos::{Lexer, Logos};
|
use logos::{Lexer, Logos};
|
||||||
|
|
||||||
|
use crate::error::{DiagnosticKind, DiagnosticReporter, FileIdent};
|
||||||
|
|
||||||
#[derive(Logos, Debug, PartialEq)]
|
#[derive(Logos, Debug, PartialEq)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
#[regex("[a-zA-Z\\d\\w]+", |lex| lex.slice().to_owned())]
|
#[regex("[a-zA-Z\\d\\s]+", |lex| lex.slice().to_owned())]
|
||||||
Text(String),
|
Text(String),
|
||||||
#[token("(")]
|
#[token("(")]
|
||||||
ParenOpen,
|
ParenOpen,
|
||||||
|
@ -40,35 +42,45 @@ pub enum LanguageStructureThingy {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_the_shit_out_of_this_but_manually(text: &str) -> Vec<LanguageStructureThingy> {
|
pub fn parse_the_shit_out_of_this_but_manually<'a>(
|
||||||
let mut lex = Token::lexer(text);
|
text: &str,
|
||||||
|
reporter: &mut DiagnosticReporter<'a>,
|
||||||
|
file_id: &'a FileIdent,
|
||||||
|
) -> Vec<LanguageStructureThingy> {
|
||||||
|
let mut lex = Token::lexer(text).spanned();
|
||||||
let mut r = Vec::new();
|
let mut r = Vec::new();
|
||||||
|
|
||||||
loop {
|
while let Some((res, loc)) = lex.next() {
|
||||||
match lex.next() {
|
match res {
|
||||||
Some(Ok(Token::Text(s))) => r.push(LanguageStructureThingy::Text(s)),
|
Ok(Token::Text(s)) => r.push(LanguageStructureThingy::Text(s)),
|
||||||
Some(Ok(Token::Newline)) => r.push(LanguageStructureThingy::Text("\n".to_owned())),
|
Ok(Token::Newline) => r.push(LanguageStructureThingy::Text("\n".to_owned())),
|
||||||
Some(Ok(Token::ParenOpen)) => hehe_sexpression_funy(&mut r, &mut lex),
|
Ok(Token::ParenOpen) => hehe_sexpression_funy(&mut r, &mut lex),
|
||||||
Some(Ok(Token::ParenClose)) => todo!(),
|
Ok(Token::String(_)) => todo!(),
|
||||||
Some(Ok(Token::String(_))) => todo!(),
|
Ok(Token::Equals) => todo!(),
|
||||||
Some(Ok(Token::Equals)) => todo!(),
|
Ok(Token::Asterisk) => todo!(),
|
||||||
Some(Ok(Token::Asterisk)) => todo!(),
|
Ok(Token::Underscore) => todo!(),
|
||||||
Some(Ok(Token::Underscore)) => todo!(),
|
Ok(Token::Backslash) => todo!(),
|
||||||
Some(Ok(Token::Backslash)) => todo!(),
|
Ok(Token::WavyThing) => todo!(),
|
||||||
Some(Ok(Token::WavyThing)) => todo!(),
|
Ok(Token::Sparkles) => todo!(),
|
||||||
Some(Ok(Token::Sparkles)) => todo!(),
|
Ok(Token::HeadingLevelIndicator) => todo!(),
|
||||||
Some(Ok(Token::HeadingLevelIndicator)) => todo!(),
|
Err(()) | Ok(Token::ParenClose) => {
|
||||||
Some(Err(e)) => panic!("mauuu~ :(, e: {e:?}"),
|
reporter.report_diagnostic(*file_id, loc, DiagnosticKind::InvalidToken)
|
||||||
None => break,
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reporter.fail_step_if_failed();
|
||||||
|
// match lex.next() {
|
||||||
|
// Some(Err(e)) => panic!("mauuu~ :(, e: {e:?}"),
|
||||||
|
// None => break,
|
||||||
|
// }
|
||||||
|
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hehe_sexpression_funy(r: &mut Vec<LanguageStructureThingy>, lex: &mut Lexer<'_, Token>) {
|
fn hehe_sexpression_funy(r: &mut Vec<LanguageStructureThingy>, lex: &mut Lexer<'_, Token>) {
|
||||||
if let Some(Ok(Token::Text(s))) = lex.next() {
|
if let Some(Ok(Token::Text(s))) = lex.next() {
|
||||||
let strs = s.trim_start().split_whitespace().collect::<Vec<&str>>();
|
let strs = s.split_whitespace().collect::<Vec<&str>>();
|
||||||
|
|
||||||
let name = strs[0].to_owned();
|
let name = strs[0].to_owned();
|
||||||
let mut attrs = HashMap::new();
|
let mut attrs = HashMap::new();
|
||||||
|
|
Loading…
Reference in a new issue