df_ls_syntax_analysis 0.3.0-rc.1

A language server for Dwarf Fortress RAW files
Documentation
use super::Token;
use df_ls_diagnostics::DiagnosticsInfo;
use df_ls_lexical_analysis::TreeCursor;

mod td_allow_empty;
mod td_any;
mod td_arg_n;
mod td_bang_arg_n;
mod td_bang_arg_n_seq;
mod td_bool;
mod td_char;
mod td_choose;
mod td_clamp;
mod td_df_char;
mod td_df_raw_file;
mod td_int;
mod td_option;
mod td_pipe_arguments;
mod td_reference;
mod td_reference_to;
mod td_string;
mod td_token;
mod td_token_argument;
mod td_tuple;
mod td_vec;

#[derive(Clone, Debug)]
pub enum LoopControl {
    DoNothing,
    Break,
    Continue,
    ErrBreak,
}

impl Default for LoopControl {
    fn default() -> Self {
        LoopControl::DoNothing
    }
}

pub trait TokenDeserialize: Sized
where
    Self: Default,
{
    fn deserialize_tokens(
        cursor: &mut TreeCursor,
        source: &str,
        diagnostics: &mut DiagnosticsInfo,
    ) -> Result<Box<Self>, ()> {
        let mut new_self = Box::new(Self::default());
        loop {
            let node = cursor.node();
            // If we reach the limit, stop parsing the file further.
            if diagnostics.check_message_limit_reached() {
                crate::mark_rest_of_file_as_unchecked(cursor, diagnostics, &node);
                break;
            }
            match node.kind().as_ref() {
                "token" => {
                    match Self::deserialize_general_token(cursor, source, diagnostics, new_self) {
                        (LoopControl::DoNothing, new_self_result) => {
                            // Do nothing
                            new_self = new_self_result;
                        }
                        (LoopControl::Break, new_self_result) => {
                            new_self = new_self_result;
                            break;
                        }
                        (LoopControl::Continue, new_self_result) => {
                            new_self = new_self_result;
                            // Only go to next sibling if there is one, if none: break.
                            // We have reached the end of the file, so have to go up the stack
                            let new_node = cursor.node();
                            if new_node.next_sibling().is_none() {
                                cursor.goto_parent();
                                break;
                            }
                            // If node did not change: break
                            // This will prevent infinite loops
                            if new_node == node {
                                break;
                            }
                            continue;
                        }
                        (LoopControl::ErrBreak, _new_self_result) => {
                            return Err(());
                        }
                    }
                }
                "comment" => {
                    // Just consume `comment` and move on to next token.
                    if Token::consume_token(cursor).is_err() {
                        break;
                    }
                }
                "ERROR" => {
                    // Can safely be ignored. Diagnostics already added by Lexical Analysis.
                    if Token::consume_token(cursor).is_err() {
                        break;
                    }
                }
                "EOF" => break,
                others => {
                    log::error!("Found an unknown node of kind: {}", others);
                    break;
                }
            }
            // If node did not change: break
            // This will prevent infinite loops
            let new_node = cursor.node();
            if new_node == node {
                break;
            }
        }
        Ok(new_self)
    }

    fn deserialize_general_token(
        cursor: &mut TreeCursor,
        source: &str,
        diagnostics: &mut DiagnosticsInfo,
        new_self: Box<Self>,
    ) -> (LoopControl, Box<Self>);

    fn get_allowed_tokens() -> Option<Vec<String>>;

    /// Should return `Continue` in most cases,
    /// `DoNothing` in case of String, i32, Tuples and type likes that
    fn get_vec_loopcontrol() -> LoopControl {
        LoopControl::Continue
    }
}