shulker 0.1.2

A build tool for the Blackstone programming language.
use std::sync::{Arc, Mutex};

use crate::codegen::misc::{BracketDirection, BracketType, VariableScope};
use crate::codegen::{block::Block, item::Item, item_data::ItemData};

use chumsky::prelude::*;
use chumsky::text::ident;

use super::datatypes::*;

pub fn parser() -> impl Parser<char, Vec<Option<Block<'static>>>, Error = Simple<char>> {
    let player_default: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));

    let ident = text::ident();
    

    

    

    // Location
    // This argument represents a Location type on diamondfire.
    // It is parsed from 3 or 5 arguments inside angle brackets.
    // loc(1, 2, 3) VALID, loc(1, 2, 3, 4, 5) VALID, loc(1, 2, 3, 4) INVALID, loc(1, 2) INVALID
    

    

    

    let arguments = text
        .or(parse_number())
        .or(location)
        .or(item)
        .or(item_stack)
        .or(variable);

    let actions = recursive(
        |actions: Recursive<char, Vec<Option<Block>>, Simple<char>>| {
            let operation = just::<char, &str, Simple<char>>("=")
                .or(just("+"))
                .or(just("-"))
                .or(just("*"))
                .or(just("/"))
                .or(just("%"));

            let repeat = text::keyword("loop")
                .ignore_then(just(' '))
                .ignore_then(ident)
                .then_ignore(just("::"))
                .then_ignore(ident)
                .padded()
                .then(
                    arguments
                        .clone()
                        .separated_by(just(", "))
                        .allow_trailing()
                        .padded()
                        .collect::<Vec<_>>()
                        .padded()
                        .delimited_by(just('('), just(')'))
                        .padded(),
                )
                .padded()
                .then(
                    actions
                        .clone()
                        .separated_by(just(';'))
                        .allow_trailing()
                        .padded()
                        .collect::<Vec<_>>()
                        .padded()
                        .delimited_by(just('{'), just('}'))
                        .padded(),
                )
                .padded()
                .map(|((label, args), codes)| {
                    let mut out = vec![];
                    for block in codes {
                        for sub_block in block.into_iter().flatten() {
                            out.append(&mut vec![Some(sub_block)]);
                        }
                    }
                    let mut items: Vec<Item> = vec![];
                    for (slot, data) in args.into_iter().enumerate() {
                        let id = data_to_id(&data);
                        items.push(Item {
                            id,
                            slot: slot.try_into().expect("failed ot convert to usize"),
                            item: data,
                        })
                    }
                    out.insert(
                        0,
                        Some(Block::Code {
                            block: "repeat",
                            items,
                            action: label,
                            data: "",
                            target: "",
                            inverted: "",
                            sub_action: String::new(),
                        }),
                    );
                    out.insert(
                        1,
                        Some(Block::Bracket {
                            direct: BracketDirection::Open,
                            typ: BracketType::Repeat,
                        }),
                    );
                    out.push(Some(Block::Bracket {
                        direct: BracketDirection::Close,
                        typ: BracketType::Repeat,
                    }));
                    out
                });

            

            
            

            type NestedType<'a> = (
                (
                    ((std::string::String, &'a str), std::string::String),
                    Vec<ItemData>,
                ),
                Vec<Vec<std::option::Option<Block<'a>>>>,
            );
            let if_else = text::keyword("if")
            .padded()
            .ignore_then(
                actions
                    .clone()
                    .separated_by(just(';'))
                    .allow_trailing()
                    .padded()
                    .collect::<Vec<_>>()
                    .padded()
                    .delimited_by(just('{'), just('}'))
                    .padded(),
            )
            .map(|args| {
                let mut out = vec![];
                for block in args {
                    for sub_block in block {
                        if let Some(bl) = sub_block {
                            out.append(&mut vec![Some(bl)]);
                        }
                    }
                }
                out.insert(
                    0,
                    Some(Block::Code {
                        block: "else",
                        items: vec![],
                        action: "".to_string(),
                        data: "",
                        target: "",
                        inverted: "",
                        sub_action: String::new(),
                    }),
                );
                out.insert(
                    1,
                    Some(Block::Bracket {
                        direct: BracketDirection::Open,
                        typ: BracketType::Norm,
                    }),
                );
                out.push(Some(Block::Bracket {
                    direct: BracketDirection::Close,
                    typ: BracketType::Norm,
                }));
                out
            });
            let if_variable = text::keyword("if")
                .padded()
                .ignore_then(text::keyword("var"))
                .padded()
                .ignore_then(ident)
                .padded()
                .then(operation)
                .padded()
                .then(ident)
                .then(
                    arguments
                        .clone()
                        .separated_by(just(", "))
                        .allow_trailing()
                        .padded()
                        .collect::<Vec<_>>()
                        .padded()
                        .delimited_by(just('('), just(')'))
                        .padded(),
                )
                .then(
                    actions
                        .clone()
                        .separated_by(just(';'))
                        .allow_trailing()
                        .padded()
                        .collect::<Vec<_>>()
                        .padded()
                        .delimited_by(just('{'), just('}'))
                        .padded(),
                )
                .padded()
                .map(
                    |((((var_name, _var_op), action), arguments), codes): NestedType| {
                        let mut out = vec![];
                        for block in codes {
                            for sub_block in block.into_iter().flatten() {
                                out.append(&mut vec![Some(sub_block)]);
                            }
                        }
                        let mut items: Vec<Item> = vec![];
                        for (slot, item) in arguments.into_iter().enumerate() {
                            let id = data_to_id(&item);

                    items.push(Item {
                        id,
                        slot: slot.try_into().expect("failed to convert to usize"),
                        item,
                    })
                }
                items.insert(0, Item {
                    id: "var".to_string(),
                    slot: 0,
                    item: ident_to_var(var_name.as_str())
                });
                out.insert(
                    0,
                    Some(Block::Code {
                        block: "if_var",
                        items: items,
                        action: action,
                        data: "",
                        target: "Selection",
                        inverted: "",
                        sub_action: String::new(),
                    }),
                );
                out.insert(
                    1,
                    Some(Block::Bracket {
                        direct: BracketDirection::Open,
                        typ: BracketType::Norm,
                    }),
                );
                out.push(Some(Block::Bracket {
                    direct: BracketDirection::Close,
                    typ: BracketType::Norm,
                }));
                out
            });

            let call_function = text::keyword("func")
                .padded()
                .ignore_then(ident)
                .padded()
                .then_ignore(just("();"))
                .map(|name| {
                    vec![
                        Some(Block::Code {
                            block: "set_var",
                            items: vec![Item {
                                id: "var".to_string(),
                                slot: 0,
                                item: ItemData::Variable {
                                    scope: VariableScope::Local,
                                    name: "__FUNCTION_PARAMETERS".to_string(),
                                },
                            }],
                            action: "CreateList".to_string(),
                            data: "",
                            target: "",
                            inverted: "",
                            sub_action: String::new(),
                        }),
                        Some(Block::FunctionCall {
                            block: "call_func",
                            data: name,
                        }),
                    ]
                });

            let start_process = text::keyword("proc")
                .padded()
                .ignore_then(ident)
                .padded()
                .then_ignore(just("();"))
                .map(|name| {
                    vec![
                        Some(Block::Code {
                            block: "set_var",
                            items: vec![Item {
                                id: "var".to_string(),
                                slot: 0,
                                item: ItemData::Variable {
                                    scope: VariableScope::Local,
                                    name: "__FUNCTION_PARAMETERS".to_string(),
                                },
                            }],
                            action: "CreateList".to_string(),
                            data: "",
                            target: "",
                            inverted: "",
                            sub_action: String::new(),
                        }),
                        Some(Block::ProcessCall {
                            block: "start_process",
                            data: name,
                        }),
                    ]
                });

            player_action
                .or(call_function)
                .or(start_process)
                .or(game_action)
                .or(if_player)
                .or(if_entity)
                .or(if_game)
                .or(if_variable)
                .or(select_object)
                .or(set_variable)
                .or(repeat)
        },
    );

    
}



fn type_command() -> impl Parser<char, Vec<Option<Block<'static>>>, Error = Simple<char>> {
    // Type Command
    // This command represents creating a type that references a selector.
    // You can use these to call different actions.
    let type_command = text::keyword("type")
        .ignore_then(just(' '))
        .ignore_then(ident())
        .padded()
        .then_ignore(just('='))
        .padded()
        .then_ignore(ident())
        .padded()
        .ignore_then(just(""))
        .map(move |varn: &str| {
            vec![None::<Block>]
        });

    type_command

}