oak-java 0.0.11

High-performance incremental Java language parser for the oak ecosystem with flexible configuration, supporting modern Java features and object-oriented programming.
Documentation
use crate::{ast::*, builder::JavaBuilder, language::JavaLanguage, lexer::token_type::JavaTokenType, parser::element_type::JavaElementType};
use oak_core::tree::red_tree::{RedNode, RedTree};

impl<'config> JavaBuilder<'config> {
    pub(crate) fn build_block(&self, node: RedNode<JavaLanguage>, source: &str) -> Vec<Statement> {
        let mut statements = Vec::new();
        for child in node.children() {
            if let RedTree::Node(sub_node) = child {
                statements.push(self.build_statement(sub_node, source))
            }
        }
        statements
    }

    pub(crate) fn build_catch_clause(&self, node: RedNode<JavaLanguage>, source: &str) -> CatchClause {
        let mut parameter = Parameter { name: "".to_string(), r#type: "".to_string() };
        let mut block = Vec::new();
        for child in node.children() {
            if let RedTree::Node(sub_node) = child {
                match sub_node.green.kind {
                    JavaElementType::Parameter => parameter = self.build_parameter(sub_node, source),
                    JavaElementType::BlockStatement => block = self.build_block(sub_node, source),
                    _ => {}
                }
            }
        }
        CatchClause { parameter, block }
    }

    pub(crate) fn build_switch_case(&self, node: RedNode<JavaLanguage>, source: &str) -> SwitchCase {
        let mut label = None;
        let mut body = Vec::new();
        for child in node.children() {
            if let RedTree::Node(sub_node) = child {
                if label.is_none() && sub_node.green.kind != JavaElementType::BlockStatement {
                    label = Some(self.build_expression(sub_node, source))
                }
                else if sub_node.green.kind == JavaElementType::BlockStatement {
                    body.extend(self.build_block(sub_node, source))
                }
                else {
                    body.push(self.build_statement(sub_node, source))
                }
            }
        }
        SwitchCase { label: label.unwrap_or(Expression::Literal(Literal::Integer(0))), body }
    }

    pub(crate) fn build_statement(&self, node: RedNode<JavaLanguage>, source: &str) -> Statement {
        match node.green.kind {
            JavaElementType::ExpressionStatement => {
                let mut expr_node = None;
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        expr_node = Some(sub_node);
                        break;
                    }
                }
                if let Some(sub_node) = expr_node {
                    let expr = self.build_expression(sub_node.clone(), source);
                    return Statement::Expression(expr);
                }
                Statement::Block(vec![])
            }
            JavaElementType::BlockStatement => Statement::Block(self.build_block(node, source)),
            JavaElementType::ReturnStatement => {
                let mut expr = None;
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        expr = Some(self.build_expression(sub_node, source));
                        break;
                    }
                }
                Statement::Return(expr)
            }
            JavaElementType::IfStatement => {
                let mut condition = None;
                let mut then_branch = None;
                let mut else_branch = None;
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        if condition.is_none() {
                            condition = Some(self.build_expression(sub_node, source))
                        }
                        else if then_branch.is_none() {
                            then_branch = Some(Box::new(self.build_statement(sub_node, source)))
                        }
                        else {
                            else_branch = Some(Box::new(self.build_statement(sub_node, source)))
                        }
                    }
                }
                Statement::If { condition: condition.unwrap_or(Expression::Literal(Literal::Boolean(true))), then_branch: then_branch.unwrap_or(Box::new(Statement::Block(vec![]))), else_branch }
            }
            JavaElementType::WhileStatement => {
                let mut condition = None;
                let mut body = None;
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        if condition.is_none() { condition = Some(self.build_expression(sub_node, source)) } else { body = Some(Box::new(self.build_statement(sub_node, source))) }
                    }
                }
                Statement::While { condition: condition.unwrap_or(Expression::Literal(Literal::Boolean(true))), body: body.unwrap_or(Box::new(Statement::Block(vec![]))) }
            }
            JavaElementType::DoWhileStatement => {
                let mut condition = None;
                let mut body = None;
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        if body.is_none() { body = Some(Box::new(self.build_statement(sub_node, source))) } else { condition = Some(self.build_expression(sub_node, source)) }
                    }
                }
                Statement::DoWhile { condition: condition.unwrap_or(Expression::Literal(Literal::Boolean(true))), body: body.unwrap_or(Box::new(Statement::Block(vec![]))) }
            }
            JavaElementType::ForStatement => {
                let mut init = None;
                let mut condition = None;
                let mut update = None;
                let mut body = None;
                let mut semicolon_count = 0;
                let mut after_right_paren = false;

                for child in node.children() {
                    match child {
                        RedTree::Leaf(leaf) => {
                            if leaf.kind == JavaTokenType::Semicolon {
                                semicolon_count += 1
                            }
                            else if leaf.kind == JavaTokenType::RightParen {
                                after_right_paren = true
                            }
                        }
                        RedTree::Node(sub_node) => {
                            if after_right_paren {
                                if body.is_none() {
                                    body = Some(Box::new(self.build_statement(sub_node, source)))
                                }
                            }
                            else {
                                match semicolon_count {
                                    0 => init = Some(Box::new(self.build_statement(sub_node, source))),
                                    1 => condition = Some(self.build_expression(sub_node, source)),
                                    2 => update = Some(self.build_expression(sub_node, source)),
                                    _ => {}
                                }
                            }
                        }
                    }
                }
                Statement::For { init, condition, update, body: body.unwrap_or(Box::new(Statement::Block(vec![]))) }
            }
            JavaElementType::SwitchStatement => {
                let mut selector = None;
                let mut cases = Vec::new();
                let mut default = None;
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        match sub_node.green.kind {
                            JavaElementType::SwitchCase => cases.push(self.build_switch_case(sub_node, source)),
                            JavaElementType::DefaultCase => default = Some(self.build_block(sub_node, source)),
                            _ => {
                                if selector.is_none() {
                                    selector = Some(self.build_expression(sub_node, source))
                                }
                            }
                        }
                    }
                }
                Statement::Switch { selector: selector.unwrap_or(Expression::Identifier("unknown_selector".to_string())), cases, default }
            }
            JavaElementType::Break => Statement::Break,
            JavaElementType::Continue => Statement::Continue,
            JavaElementType::TryStatement => {
                let mut block = Vec::new();
                let mut catches = Vec::new();
                let mut finally = None;
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        match sub_node.green.kind {
                            JavaElementType::BlockStatement => {
                                if block.is_empty() {
                                    block = self.build_block(sub_node, source);
                                }
                                else {
                                    finally = Some(self.build_block(sub_node, source));
                                }
                            }
                            JavaElementType::CatchClause => catches.push(self.build_catch_clause(sub_node, source)),
                            _ => {}
                        }
                    }
                }
                Statement::Try(TryStatement { block, catches, finally })
            }
            JavaElementType::ThrowStatement => {
                for child in node.children() {
                    if let RedTree::Node(sub_node) = child {
                        return Statement::Throw(self.build_expression(sub_node, source));
                    }
                }
                Statement::Throw(Expression::Identifier("unknown_throw".to_string()))
            }
            JavaElementType::VariableDeclaration => {
                let mut r#type = String::new();
                let mut name = String::new();
                let mut initializer = None;

                for child in node.children() {
                    match child {
                        RedTree::Leaf(leaf) => match leaf.kind {
                            JavaTokenType::Identifier => {
                                if r#type.is_empty() {
                                    r#type = self.get_text(leaf.span, source).to_string()
                                }
                                else if name.is_empty() {
                                    name = self.get_text(leaf.span, source).to_string()
                                }
                            }
                            JavaTokenType::Int | JavaTokenType::Boolean | JavaTokenType::Void | JavaTokenType::Long | JavaTokenType::Float | JavaTokenType::Double | JavaTokenType::Char | JavaTokenType::Byte | JavaTokenType::Short => {
                                if r#type.is_empty() {
                                    r#type = self.get_text(leaf.span, source).to_string()
                                }
                            }
                            JavaTokenType::LeftBracket => {
                                if !r#type.is_empty() {
                                    r#type.push_str("[]")
                                }
                            }
                            _ => {}
                        },
                        RedTree::Node(sub_node) => {
                            if sub_node.green.kind == JavaElementType::Identifier {
                                if r#type.is_empty() {
                                    r#type = self.extract_identifier(sub_node, source)
                                }
                                else if name.is_empty() {
                                    name = self.extract_identifier(sub_node, source)
                                }
                                else {
                                    initializer = Some(self.build_expression(sub_node, source))
                                }
                            }
                            else {
                                initializer = Some(self.build_expression(sub_node, source))
                            }
                        }
                    }
                }
                Statement::LocalVariable { r#type, name, initializer }
            }
            _ => Statement::Block(vec![]),
        }
    }
}