#![forbid(unsafe_code)]
#![deny(clippy::all)]
#![allow(clippy::result_unit_err)]
mod token_deserializers;
mod utils;
#[cfg(debug_assertions)]
pub mod test_utils;
use colored::*;
pub use df_ls_derive::TokenDeserialize;
use df_ls_diagnostics::lsp_types::{Diagnostic, DiagnosticSeverity};
use df_ls_diagnostics::{hash_map, DMExtraInfo, DiagnosticMessageSet, DiagnosticsInfo};
pub use df_ls_lexical_analysis::{Node, Tree, TreeCursor};
use std::collections::HashMap;
pub use token_deserializers::{
Argument, LoopControl, Token, TokenArgument, TokenDeserialize, TokenDeserializeBasics,
TryFromArgument, TryFromArgumentGroup,
};
pub use utils::mark_rest_of_token_as_unchecked;
pub(crate) use utils::*;
pub fn do_syntax_analysis<T: TokenDeserialize>(tree: &Tree, source: &str) -> (T, DiagnosticsInfo) {
do_syntax_analysis_direct(tree, source, true)
}
pub fn do_syntax_analysis_direct<T: TokenDeserialize>(
tree: &Tree,
source: &str,
load_diagnostic_messages: bool,
) -> (T, DiagnosticsInfo) {
let mut tree_cursor = tree.walk();
tree_cursor.goto_first_child();
let mut diagnostic_info = if load_diagnostic_messages {
DiagnosticsInfo::load_from_file(
DiagnosticMessageSet::Syntax,
Some("DF RAW Language Server".to_owned()),
)
} else {
DiagnosticsInfo::new(HashMap::new(), Some("DF RAW Language Server".to_owned()))
};
let structure = match TokenDeserialize::deserialize_tokens(
&mut tree_cursor,
source,
&mut diagnostic_info,
) {
Ok(value) => {
let new_node = tree_cursor.node();
if new_node.next_sibling().is_none() {
tree_cursor.goto_parent();
} else {
if let Ok(token) =
Token::deserialize_tokens(&mut tree_cursor, source, &mut diagnostic_info)
{
let token_name = match token.get_token_name() {
Ok(token_name) => token_name.value.to_owned(),
Err(_) => "TokenName is missing".to_owned(),
};
diagnostic_info.add_message(
DMExtraInfo {
range: new_node.get_range(),
message_template_data: hash_map! {
"token_name" => format!("`{}`", token_name),
},
},
"unknown_token",
);
}
mark_rest_of_file_as_unchecked(&mut tree_cursor, &mut diagnostic_info, &new_node);
}
*value
}
Err(_) => {
let new_node = tree_cursor.node();
diagnostic_info
.add_message(DMExtraInfo::new(new_node.get_range()), "token_not_expected");
mark_rest_of_file_as_unchecked(&mut tree_cursor, &mut diagnostic_info, &new_node);
T::default()
}
};
(structure, diagnostic_info)
}
pub fn print_source_with_diagnostics(source: &str, diagnostics: &[Diagnostic]) {
println!("--------Output---------");
for (line_nr, line) in source.split('\n').enumerate() {
let mut new_line = "".to_owned();
for (ch_nr, ch) in line.chars().enumerate() {
match get_pos_severity(line_nr as u32, ch_nr as u32, diagnostics) {
Some(severity) => {
let ch_str = ch.to_string();
#[allow(clippy::unnecessary_to_owned)]
match severity {
DiagnosticSeverity::INFORMATION => {
new_line.push_str(&ch_str.bright_blue().to_string())
}
DiagnosticSeverity::HINT => {
new_line.push_str(&ch_str.bright_blue().to_string())
}
DiagnosticSeverity::WARNING => {
new_line.push_str(&ch_str.bright_yellow().to_string())
}
DiagnosticSeverity::ERROR => {
new_line.push_str(&ch_str.bright_red().to_string())
}
_ => {
unreachable!("This severity does not exist currently");
}
}
}
None => new_line.push(ch),
}
}
println!("{}", new_line);
}
println!("----------------------");
}
fn get_pos_severity(
line: u32,
character: u32,
diagnostics: &[Diagnostic],
) -> Option<DiagnosticSeverity> {
let mut severity = None;
for item in diagnostics {
if line >= item.range.start.line && line <= item.range.end.line {
if line > item.range.start.line && line < item.range.end.line {
if severity < item.severity || severity.is_none() {
severity = item.severity;
}
}
else if line < item.range.end.line {
if character >= item.range.start.character {
if severity < item.severity || severity.is_none() {
severity = item.severity;
}
}
}
else if line > item.range.start.line {
if character < item.range.end.character {
if severity < item.severity || severity.is_none() {
severity = item.severity;
}
}
}
else if character >= item.range.start.character
&& character < item.range.end.character
{
if severity < item.severity || severity.is_none() {
severity = item.severity;
}
}
}
}
severity
}