chrobry-core 1.1.1

Chrobry core module
Documentation
use crate::ast::*;
use pest::{iterators::Pair, Parser};
use std::collections::HashMap;

pub fn parse(content: &str) -> Result<Ast, String> {
    let program = match AstParser::parse(Rule::program, content) {
        Ok(mut pairs) => pairs.next().unwrap(),
        Err(error) => return Err(format!("{:#?}", error)),
    };
    let mut ast = Ast::default();
    for pair in program.into_inner() {
        match pair.as_rule() {
            Rule::import_elm => ast.imports.push(parse_import(pair)),
            Rule::inject_elm => ast.injects.push(parse_inject(pair)),
            Rule::replace_elm => ast.replacements.push(parse_replace(pair)),
            Rule::extern_elm => ast.externs.push(parse_extern(pair)),
            Rule::struct_elm => ast.structs.push(parse_struct(pair)),
            Rule::enum_elm => ast.enums.push(parse_enum(pair)),
            Rule::impl_elm => ast.implementations.push(parse_implementation(pair)),
            Rule::EOI => {}
            _ => panic!("{:?}", pair.as_rule()),
        }
    }
    Ok(ast)
}

fn parse_import(pair: Pair<Rule>) -> String {
    parse_string(pair.into_inner().next().unwrap())
}

fn parse_inject(pair: Pair<Rule>) -> AstCode {
    parse_code(pair.into_inner().next().unwrap())
}

fn parse_replace(pair: Pair<Rule>) -> AstReplace {
    let mut pairs = pair.into_inner();
    let pattern = parse_string(pairs.next().unwrap()).replace("\\\\", "\\");
    let template = parse_code(pairs.next().unwrap());
    AstReplace { pattern, template }
}

fn parse_extern(pair: Pair<Rule>) -> AstExtern {
    let mut pairs = pair.into_inner();
    let types = parse_extern_types(pairs.next().unwrap());
    let implementations = parse_extern_implementations(pairs.next().unwrap());
    AstExtern {
        types,
        implementations,
    }
}

fn parse_extern_types(pair: Pair<Rule>) -> Vec<String> {
    pair.into_inner().map(parse_string).collect::<Vec<_>>()
}

fn parse_extern_implementations(pair: Pair<Rule>) -> Vec<(String, AstCode)> {
    pair.into_inner()
        .map(parse_extern_implementation)
        .collect::<Vec<_>>()
}

fn parse_extern_implementation(pair: Pair<Rule>) -> (String, AstCode) {
    let mut pairs = pair.into_inner();
    let identifier = parse_identifier(pairs.next().unwrap());
    let code = parse_code(pairs.next().unwrap());
    (identifier, code)
}

fn parse_struct(pair: Pair<Rule>) -> AstStruct {
    let mut result = AstStruct::default();
    for pair in pair.into_inner() {
        match pair.as_rule() {
            Rule::tags => result.tags = parse_tags(pair),
            Rule::identifier => result.name = parse_identifier(pair),
            Rule::fields => result.fields = parse_struct_fields(pair),
            _ => panic!("{:?}", pair.as_rule()),
        }
    }
    result
}

fn parse_struct_fields(pair: Pair<Rule>) -> Vec<(String, AstType)> {
    pair.into_inner()
        .map(parse_struct_field)
        .collect::<Vec<_>>()
}

fn parse_struct_field(pair: Pair<Rule>) -> (String, AstType) {
    let mut pairs = pair.into_inner();
    let identifier = parse_identifier(pairs.next().unwrap());
    let type_ = parse_type(pairs.next().unwrap());
    (identifier, type_)
}

fn parse_enum(pair: Pair<Rule>) -> AstEnum {
    let mut result = AstEnum::default();
    for pair in pair.into_inner() {
        match pair.as_rule() {
            Rule::tags => result.tags = parse_tags(pair),
            Rule::identifier => result.name = parse_identifier(pair),
            Rule::enum_fields => result.fields = parse_enum_fields(pair),
            _ => panic!("{:?}", pair.as_rule()),
        }
    }
    result
}

fn parse_enum_fields(pair: Pair<Rule>) -> Vec<String> {
    pair.into_inner().map(parse_identifier).collect::<Vec<_>>()
}

fn parse_implementation(pair: Pair<Rule>) -> AstImplementation {
    let mut result = AstImplementation::default();
    for pair in pair.into_inner() {
        match pair.as_rule() {
            Rule::impl_target => result.target = parse_implementation_target(pair),
            Rule::identifier => result.name = parse_identifier(pair),
            Rule::where_rules => result.where_rules = parse_where_rules(pair),
            Rule::code => result.code = parse_code(pair),
            _ => panic!("{:?}", pair.as_rule()),
        }
    }
    result
}

fn parse_implementation_target(pair: Pair<Rule>) -> AstImplementationTarget {
    let pair = pair.into_inner().next().unwrap();
    match pair.as_rule() {
        Rule::impl_target_struct => AstImplementationTarget::Struct,
        Rule::impl_target_enum => AstImplementationTarget::Enum,
        _ => panic!("{:?}", pair.as_rule()),
    }
}

fn parse_type(pair: Pair<Rule>) -> AstType {
    let pair = pair.into_inner().next().unwrap();
    match pair.as_rule() {
        Rule::string => AstType::Extern(parse_string(pair)),
        Rule::identifier => AstType::Local(parse_identifier(pair)),
        _ => panic!("{:?}", pair.as_rule()),
    }
}

fn parse_tags(pair: Pair<Rule>) -> Vec<(String, HashMap<String, String>)> {
    pair.into_inner().map(parse_tag).collect::<Vec<_>>()
}

fn parse_tag(pair: Pair<Rule>) -> (String, HashMap<String, String>) {
    let mut pairs = pair.into_inner();
    let identifier = parse_identifier(pairs.next().unwrap());
    let parameters = if let Some(pair) = pairs.next() {
        pair.into_inner()
            .map(parse_tag_parameter)
            .collect::<HashMap<_, _>>()
    } else {
        Default::default()
    };
    (identifier, parameters)
}

fn parse_tag_parameter(pair: Pair<Rule>) -> (String, String) {
    let mut pairs = pair.into_inner();
    let identifier = parse_identifier(pairs.next().unwrap());
    let value = if let Some(pair) = pairs.next() {
        parse_string(pair)
    } else {
        Default::default()
    };
    (identifier, value)
}

fn parse_code(pair: Pair<Rule>) -> AstCode {
    let pair = pair.into_inner().next().unwrap();
    let mut code = AstCode::default();
    for pair in pair.into_inner() {
        match pair.as_rule() {
            Rule::code_chars => {
                code.0.push(AstCodeChunk::Content(pair.as_str().to_owned()));
            }
            Rule::code_op => {
                let pair = pair.into_inner().next().unwrap();
                match pair.as_rule() {
                    Rule::variable => {
                        code.0.push(AstCodeChunk::Variable(parse_variable(pair)));
                    }
                    Rule::code_op_for => {
                        code.0.push(AstCodeChunk::For(parse_code_for(pair)));
                    }
                    _ => panic!("{:?}", pair.as_rule()),
                }
            }
            _ => panic!("{:?}", pair.as_rule()),
        }
    }
    code
}

fn parse_code_for(pair: Pair<Rule>) -> AstCodeFor {
    let mut result = AstCodeFor::default();
    for pair in pair.into_inner() {
        match pair.as_rule() {
            Rule::vars => result.variables = parse_variables(pair),
            Rule::code_op_in => result.container = parse_in(pair),
            Rule::where_rules => result.where_rules = parse_where_rules(pair),
            Rule::code => result.code = parse_code(pair),
            _ => panic!("{:?}", pair.as_rule()),
        }
    }
    result
}

fn parse_in(pair: Pair<Rule>) -> AstIn {
    let pair = pair.into_inner().next().unwrap();
    match pair.as_rule() {
        Rule::variable => AstIn::Variable(parse_variable(pair)),
        Rule::code_op_in_fields => AstIn::Fields,
        _ => panic!("{:?}", pair.as_rule()),
    }
}

fn parse_where_rules(pair: Pair<Rule>) -> Vec<AstWhereRule> {
    pair.into_inner().map(parse_where_rule).collect::<Vec<_>>()
}

fn parse_where_rule(pair: Pair<Rule>) -> AstWhereRule {
    let pair = pair.into_inner().next().unwrap();
    match pair.as_rule() {
        Rule::where_rule_exists => {
            AstWhereRule::Exists(parse_variable(pair.into_inner().next().unwrap()))
        }
        Rule::where_rule_is => AstWhereRule::Is(parse_where_rule_is(pair)),
        Rule::where_rule_impl => AstWhereRule::Impl(parse_where_rule_impl(pair)),
        _ => panic!("{:?}", pair.as_rule()),
    }
}

fn parse_where_rule_is(pair: Pair<Rule>) -> AstWhereRuleIs {
    let mut pairs = pair.into_inner();
    let variable = parse_variable(pairs.next().unwrap());
    let value = parse_string(pairs.next().unwrap());
    AstWhereRuleIs { variable, value }
}

fn parse_where_rule_impl(pair: Pair<Rule>) -> AstWhereRuleImpl {
    let mut pairs = pair.into_inner();
    let container = parse_in(pairs.next().unwrap());
    let implements = pairs
        .next()
        .unwrap()
        .into_inner()
        .map(parse_identifier)
        .collect::<Vec<_>>();
    AstWhereRuleImpl {
        container,
        implements,
    }
}

fn parse_variables(pair: Pair<Rule>) -> Vec<String> {
    pair.into_inner().map(parse_variable).collect::<Vec<_>>()
}

fn parse_string(pair: Pair<Rule>) -> String {
    pair.into_inner().next().unwrap().as_str().to_owned()
}

fn parse_identifier(pair: Pair<Rule>) -> String {
    pair.as_str().to_owned()
}

fn parse_variable(pair: Pair<Rule>) -> String {
    pair.into_inner().next().unwrap().as_str().to_owned()
}