Skip to content

Commit

Permalink
♻️ (parser): Refactor parser
Browse files Browse the repository at this point in the history
semver: chore
  • Loading branch information
Somfic committed Jul 9, 2024
1 parent e9eaa7b commit c9beb7f
Show file tree
Hide file tree
Showing 16 changed files with 467 additions and 898 deletions.
160 changes: 105 additions & 55 deletions src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,125 @@
use crate::scanner::lexeme::Token;
use std::collections::HashSet;

use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};

use crate::{files::Files, scanner::lexeme::Token};

pub struct PassResult<'a, T> {
pub result: T,
pub diagnostics: HashSet<Diagnostic<'a>>,
}

impl<'a, T> PassResult<'a, T> {
pub fn new(result: T, diagnostics: HashSet<Diagnostic<'a>>) -> Self {
Self {
result,
diagnostics,
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Diagnostic<'a> {
pub severity: Severity,
pub code: String,
pub title: String,
pub errors: Vec<Error<'a>>,
pub snippets: Vec<Snippet<'a>>,
pub notes: Vec<String>,
}

impl<'a> Diagnostic<'a> {
pub fn error(code: impl Into<String>, message: impl Into<String>) -> Diagnostic<'a> {
Diagnostic::new(Severity::Error, code, message)
}

pub fn warning(code: impl Into<String>, message: impl Into<String>) -> Diagnostic<'a> {
Diagnostic::new(Severity::Warning, code, message)
}

pub fn note(code: impl Into<String>, message: impl Into<String>) -> Diagnostic<'a> {
Diagnostic::new(Severity::Note, code, message)
}

pub fn help(code: impl Into<String>, message: impl Into<String>) -> Diagnostic<'a> {
Diagnostic::new(Severity::Help, code, message)
}

pub fn new(
severity: Severity,
code: impl Into<String>,
message: impl Into<String>,
) -> Diagnostic<'a> {
Diagnostic {
severity,
title: message.into(),
snippets: vec![],
code: code.into(),
notes: vec![],
}
}

pub fn with_snippet(mut self, snippet: Snippet<'a>) -> Self {
self.snippets.push(snippet);
self
}

pub fn with_snippets(mut self, snippets: impl IntoIterator<Item = Snippet<'a>>) -> Self {
self.snippets.extend(snippets);
self
}

pub fn with_note(mut self, note: impl Into<String>) -> Self {
self.notes.push(note.into());
self
}

pub fn with_notes(mut self, notes: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.notes.extend(notes.into_iter().map(|note| note.into()));
self
}

pub(crate) fn transform_range(mut self, tokens: &'a [Token<'a>]) -> Diagnostic<'a> {
self.snippets = self
.snippets
.into_iter()
.map(|snippet| {
let range = snippet.range.to_source_code_range(tokens);
Snippet {
message: snippet.message,
label: snippet.label,
range,
}
})
.collect();

self
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Error<'a> {
pub struct Snippet<'a> {
pub message: String,
pub label: Label,
pub range: Range<'a>,
pub notes: Vec<String>,
}

impl<'a> Error<'a> {
impl<'a> Snippet<'a> {
pub fn primary(
file_id: impl Into<&'a str>,
position: usize,
length: usize,
message: impl Into<String>,
) -> Error<'a> {
Error::new(file_id, Label::Primary, position, length, message)
) -> Snippet<'a> {
Snippet::new(file_id, Label::Primary, position, length, message)
}

pub fn secondary(
file_id: impl Into<&'a str>,
position: usize,
length: usize,
message: impl Into<String>,
) -> Error<'a> {
Error::new(file_id, Label::Secondary, position, length, message)
) -> Snippet<'a> {
Snippet::new(file_id, Label::Secondary, position, length, message)
}

pub fn new(
Expand All @@ -40,28 +128,17 @@ impl<'a> Error<'a> {
position: usize,
length: usize,
message: impl Into<String>,
) -> Error<'a> {
Error {
) -> Snippet<'a> {
Snippet {
message: message.into(),
label,
range: Range {
file_id: file_id.into(),
position,
length,
},
notes: vec![],
}
}

pub fn with_note(mut self, note: impl Into<String>) -> Self {
self.notes.push(note.into());
self
}

pub(crate) fn transform_range(mut self, lexemes: &'a [Token<'a>]) -> Error {
self.range = self.range.to_source_code_range(lexemes);
self
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -89,51 +166,24 @@ impl From<Severity> for codespan_reporting::diagnostic::Severity {
}
}

impl<'a> Diagnostic<'a> {
pub fn error(message: impl Into<String>) -> Diagnostic<'a> {
Diagnostic::new(Severity::Error, message)
}

pub fn warning(message: impl Into<String>) -> Diagnostic<'a> {
Diagnostic::new(Severity::Warning, message)
}

pub fn new(severity: Severity, message: impl Into<String>) -> Diagnostic<'a> {
Diagnostic {
severity,
title: message.into(),
errors: vec![],
}
}

pub fn with_error(mut self, error: Error<'a>) -> Self {
self.errors.push(error);
self
}
}

impl<'a> From<Diagnostic<'a>> for codespan_reporting::diagnostic::Diagnostic<&'a str> {
fn from(val: Diagnostic<'a>) -> Self {
codespan_reporting::diagnostic::Diagnostic::<&'a str>::new(val.severity.into())
.with_message(val.title)
.with_labels(
val.errors
val.snippets
.clone()
.into_iter()
.map(|error| error.into())
.map(|snippet| snippet.into())
.collect(),
)
.with_notes(
val.errors
.iter()
.flat_map(|e| e.notes.clone())
.collect::<Vec<String>>(),
)
.with_notes(val.notes)
.with_code(val.code)
}
}

impl<'a> From<Error<'a>> for codespan_reporting::diagnostic::Label<&'a str> {
fn from(val: Error<'a>) -> Self {
impl<'a> From<Snippet<'a>> for codespan_reporting::diagnostic::Label<&'a str> {
fn from(val: Snippet<'a>) -> Self {
codespan_reporting::diagnostic::Label::new(
val.label.into(),
val.range.file_id,
Expand Down
26 changes: 5 additions & 21 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,14 @@ fn main() -> Result<()> {
files.insert(file, source);

let scanner = scanner::Scanner::new(&files);
let (tokens, scanner_diagnostics) = scanner.parse();
let scanner_pass = scanner.parse();

print_diagnostics(scanner_diagnostics, &files);
//sscanner_pass.print_diagnostics(&files);

let mut parser = parser::Parser::new(&tokens);
let (ast, parser_diagnostics) = parser.parse();
let mut parser = parser::Parser::new(&scanner_pass.result);
let parser_pass = parser.parse();

print_diagnostics(parser_diagnostics, &files);
parser.print_diagnostics(&files);

Ok(())
}

fn print_diagnostics(diagnostics: HashSet<Diagnostic>, files: &Files) {
for diagnostic in diagnostics.iter() {
println!("{:?}", diagnostic);
}

let diagnostics: Vec<codespan_reporting::diagnostic::Diagnostic<&str>> =
diagnostics.iter().map(|d| d.clone().into()).collect();

let writer = StandardStream::stderr(ColorChoice::Auto);
let config = codespan_reporting::term::Config::default();

for diagnostic in diagnostics {
term::emit(&mut writer.lock(), &config, files, &diagnostic).unwrap();
}
}
3 changes: 2 additions & 1 deletion src/parser/ast.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::{HashMap, HashSet};

use crate::scanner::lexeme::Token;
use crate::{diagnostic::Range, scanner::lexeme::Token};

#[derive(Debug, Clone, PartialEq)]
pub enum Symbol<'a> {
Expand All @@ -15,6 +15,7 @@ pub enum Expression {
Number(f64),
String(String),
Identifier(String),
Boolean(bool),
Unary(UnaryOperation, Box<Expression>),
Binary(Box<Expression>, BinaryOperation, Box<Expression>),
Grouping(Box<Expression>),
Expand Down
Loading

0 comments on commit c9beb7f

Please sign in to comment.