df_ls_syntax_analysis 0.3.0-rc.1

A language server for Dwarf Fortress RAW files
Documentation
use super::super::{Argument, Token, TokenArgument, TokenName};
use super::{LoopControl, TokenDeserialize};
use crate::TokenDeserializeBasics;
use df_ls_diagnostics::DiagnosticsInfo;
use df_ls_lexical_analysis::TreeCursor;

/// Deserialize a token with any pattern
impl TokenDeserialize for Token {
    fn deserialize_tokens(
        cursor: &mut TreeCursor,
        source: &str,
        diagnostics: &mut DiagnosticsInfo,
    ) -> Result<Box<Self>, ()> {
        // Set the whole `token` as token node
        let node = cursor.node();
        let mut new_self = Box::new(Self {
            node: Some(node),
            ..Default::default()
        });
        // Go into `token`
        cursor.goto_first_child();
        loop {
            let node = cursor.node();
            match node.kind().as_ref() {
                "[" | "]" => { /* Do nothing */ }
                "token_name" => {
                    if let Ok(value) =
                        TokenDeserializeBasics::deserialize_tokens(cursor, source, diagnostics)
                    {
                        new_self.name = Some(TokenName { node, value });
                    };
                }
                "token_arguments" => {
                    match deserialize_token_arguments(cursor, source, diagnostics) {
                        Ok(mut other_arguments) => new_self.arguments.append(&mut other_arguments),
                        Err(err) => {
                            // Go out of `token`
                            cursor.goto_parent();
                            return Err(err);
                        }
                    }
                }
                "ERROR" => {
                    // Can safely be ignored. Diagnostics already added by Lexical Analysis.
                }
                "EOF" => break,
                others => {
                    log::error!("Found an unknown node of kind: `{}`", others);
                    break;
                }
            }
            // Check if there is a next sibling
            if !cursor.goto_next_sibling() {
                break;
            }
        }
        // Go out of `token`
        cursor.goto_parent();

        if new_self.name.is_none() {
            // Something went wrong during parsing or this token is empty
            log::error!("Token Name was not found: {:?}", cursor.node());
            // Skip this token as it will never be parsed
            cursor.goto_next_sibling();
        }

        Ok(new_self)
    }

    fn deserialize_general_token(
        _cursor: &mut TreeCursor,
        _source: &str,
        _diagnostics: &mut DiagnosticsInfo,
        new_self: Box<Self>,
    ) -> (LoopControl, Box<Self>) {
        (LoopControl::DoNothing, new_self)
    }

    fn get_vec_loopcontrol() -> LoopControl {
        LoopControl::DoNothing
    }

    fn get_allowed_tokens() -> Option<Vec<String>> {
        None
    }
}

pub(super) fn deserialize_token_arguments(
    cursor: &mut TreeCursor,
    source: &str,
    diagnostics: &mut DiagnosticsInfo,
) -> Result<Vec<Argument>, ()> {
    // Go into token
    cursor.goto_first_child();
    let mut argument_list = vec![];
    loop {
        let node = cursor.node();
        match node.kind().as_ref() {
            ":" => { /* Do nothing */ }
            "|" => { /* Do nothing, function is reused for pipe arguments */ }
            "token_argument_integer"
            | "token_argument_character"
            | "token_argument_arg_n"
            | "token_argument_reference"
            | "token_argument_string"
            | "token_argument_pipe_arguments"
            | "token_argument_empty"
            | "token_argument_bang_arg_n_sequence"
            | "token_argument_bang_arg_n" => {
                match TokenArgument::deserialize_tokens(cursor, source, diagnostics) {
                    Ok(value) => argument_list.push(Argument {
                        node,
                        value: *value,
                    }),
                    Err(err) => {
                        // Go out of token_arguments
                        cursor.goto_parent();
                        return Err(err);
                    }
                }
            }
            "ERROR" => {
                // Can safely be ignored. Diagnostics already added by Lexical Analysis.
            }
            "EOF" => break,
            others => {
                log::error!("Found an unknown node of kind: `{}`", others);
                break;
            }
        }
        // Check if there is a next sibling
        if !cursor.goto_next_sibling() {
            break;
        }
    }
    // Go out of token_arguments
    cursor.goto_parent();

    Ok(argument_list)
}