Skip to content

Commit

Permalink
lsp: add support for diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
oysandvik94 committed Sep 10, 2024
1 parent 2caae8b commit 8c0286b
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 7 deletions.
13 changes: 11 additions & 2 deletions crates/interpreter/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<'a> Parser<'a> {

#[derive(Debug)]
pub struct StatementError {
parse_error: ParseError,
pub parse_error: ParseError,
statement_type: StatementErrorType,
}

Expand Down Expand Up @@ -154,7 +154,16 @@ impl Display for StatementError {
},
_ => writeln!(f, "{}", self.parse_error),
},
StatementErrorType::Expression => writeln!(f, "{}", self.parse_error),
StatementErrorType::Expression => match &self.parse_error.kind {
ParseErrorKind::NoPrefixExpression => match &self.parse_error.token.token_kind {
TokenKind::Colon => writeln!(
f,
"Found an unexpected colon. Did you intend to write a `let` statement?"
),
_ => writeln!(f, "{}", self.parse_error),
},
_ => writeln!(f, "{}", self.parse_error),
},
}
}
}
Expand Down
15 changes: 14 additions & 1 deletion crates/interpreter/src/parser/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct Lexer<'a> {
chars: Chars<'a>,
current_pos: usize,
current_token: Option<Token>,
current_line_number: u16,
current_line_number: u32,
}

impl<'a> Lexer<'a> {
Expand Down Expand Up @@ -53,13 +53,18 @@ impl<'a> Lexer<'a> {

fn advance(&mut self) {
self.current_token = if let Some(c) = self.chars.next() {
let start = self.current_pos;
self.current_pos += c.len_utf8();
let end = self.current_pos;

let token_kind = self.tokenize(c);

let token = Token {
token_kind,
location: Location {
line_number: self.current_line_number,
start,
end,
},
};
Some(token)
Expand Down Expand Up @@ -94,6 +99,8 @@ impl<'a> Lexer<'a> {
// TODO: need to figure out last line of file
location: Location {
line_number: self.current_line_number,
start: self.current_pos,
end: self.current_pos,
},
},
ParseErrorKind::ExpectedToken,
Expand All @@ -115,6 +122,8 @@ impl<'a> Lexer<'a> {
token_kind: TokenKind::EOF,
location: Location {
line_number: self.current_line_number,
start: self.current_pos,
end: self.current_pos,
},
},
ParseErrorKind::ExpectedToken,
Expand Down Expand Up @@ -284,6 +293,8 @@ impl<'a> Lexer<'a> {
token_kind: TokenKind::EOF,
location: Location {
line_number: self.current_line_number,
start: self.current_pos,
end: self.current_pos,
},
},
ParseErrorKind::ExpectedToken,
Expand Down Expand Up @@ -311,6 +322,8 @@ impl<'a> Lexer<'a> {
token_kind: TokenKind::EOF,
location: Location {
line_number: self.current_line_number,
start: self.current_pos,
end: self.current_pos,
},
},
ParseErrorKind::ExpectedToken,
Expand Down
4 changes: 3 additions & 1 deletion crates/interpreter/src/parser/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ impl Debug for Token {

#[derive(PartialEq, Debug, Clone, Eq, PartialOrd, Ord)]
pub struct Location {
pub line_number: u16,
pub line_number: u32,
pub start: usize,
pub end: usize,
}

#[derive(PartialEq, Debug, Clone, PartialOrd, Ord, Eq)]
Expand Down
18 changes: 17 additions & 1 deletion crates/son_of_anton/src/lsp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod diagnostics;
pub mod document_change;
mod document_open;
pub mod initialize;
Expand All @@ -8,7 +9,9 @@ use std::process::exit;
use anyhow::anyhow;
use anyhow::Result;
use lsp_types::{
DidChangeTextDocumentParams, DidOpenTextDocumentParams, InitializeParams, InitializedParams,
DidChangeTextDocumentParams, DidOpenTextDocumentParams, DocumentDiagnosticParams,
FullDocumentDiagnosticReport, InitializeParams, InitializedParams,
RelatedFullDocumentDiagnosticReport,
};
use serde::{de::DeserializeOwned, Serialize};
use serde_json::from_str;
Expand Down Expand Up @@ -53,6 +56,19 @@ impl SonOfAnton {
let params: DidChangeTextDocumentParams = deserialize_request(&lsp_request)?;
document_change::handle_change(params, self)?;
}
"textDocument/diagnostic" => {
let params: DocumentDiagnosticParams = deserialize_request(&lsp_request)?;

let diagnostics = diagnostics::run_diagnostics(params.text_document.uri, self)?;
let response = RelatedFullDocumentDiagnosticReport {
related_documents: None,
full_document_diagnostic_report: FullDocumentDiagnosticReport {
result_id: None,
items: diagnostics,
},
};
self.send_response(lsp_request, response)?;
}
"initialized" => {
let _ = deserialize_request::<InitializedParams>(&lsp_request)?;
event!(Level::INFO, "Server was initialized");
Expand Down
38 changes: 38 additions & 0 deletions crates/son_of_anton/src/lsp/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
pub(crate) use anyhow::Result;

use interpreter::parser::{ParsedProgram, Parser};
use lsp_types::{Diagnostic, DiagnosticSeverity, Range, Uri};

use super::SonOfAnton;

pub fn run_diagnostics(uri: Uri, lsp: &mut SonOfAnton) -> Result<Vec<Diagnostic>> {
let mut parser = Parser::new(lsp.document_store.get_document(&uri)?);
let parse_result = parser.parse_program();

Ok(match parse_result {
ParsedProgram::ValidProgram(_) => Vec::with_capacity(0),
ParsedProgram::InvalidProgram(errors) => errors
.iter()
.map(|error| {
let error_location = &error.parse_error.token.location;
let range = Range {
start: lsp_types::Position {
line: error_location.line_number - 1,
character: 0,
},
end: lsp_types::Position {
line: error_location.line_number,
character: 0,
},
};
Diagnostic {
range,
severity: Some(DiagnosticSeverity::ERROR),
source: Some("piperscript".to_owned()),
message: error.to_string(),
..Default::default()
}
})
.collect(),
})
}
9 changes: 7 additions & 2 deletions crates/son_of_anton/src/lsp/initialize.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
use lsp_types::{
HoverProviderCapability, InitializeResult, ServerCapabilities, ServerInfo,
TextDocumentSyncCapability, TextDocumentSyncKind,
DiagnosticOptions, DiagnosticServerCapabilities, HoverProviderCapability, InitializeResult,
ServerCapabilities, ServerInfo, TextDocumentSyncCapability, TextDocumentSyncKind,
};

pub fn handle_initialize() -> InitializeResult {
InitializeResult {
capabilities: ServerCapabilities {
hover_provider: Some(HoverProviderCapability::Simple(true)),
text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::FULL)),
diagnostic_provider: Some(DiagnosticServerCapabilities::Options(DiagnosticOptions {
inter_file_dependencies: false,
workspace_diagnostics: false,
..Default::default()
})),
..Default::default()
},
server_info: Some(ServerInfo {
Expand Down

0 comments on commit 8c0286b

Please sign in to comment.