1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
pub mod data;
pub mod error_format;
pub mod interpreter;
pub mod linter;
pub mod parser;

use crate::data::context::get_hashmap;
use crate::linter::linter::linter;
use crate::linter::Linter;
use data::{ast::*, ContextJson, Data, Event, MessageData, MSG};
use error_format::*;
use interpreter::interpret_scope;
use parser::parse_flow;
use parser::state_context::StateContext;

use curl::easy::Easy;
use std::{collections::HashMap, sync::mpsc};

pub fn search_for<'a>(flow: &'a Flow, name: &str) -> Option<&'a Expr> {
    flow.flow_instructions
        .get(&InstructionType::NormalStep(name.to_owned()))
}

pub fn execute_step(
    flow: &Flow,
    name: &str,
    mut data: Data,
    instruction_index: Option<usize>,
    sender: &Option<mpsc::Sender<MSG>>,
) -> Result<MessageData, ErrorInfo> {
    match search_for(flow, name) {
        Some(Expr::Scope { scope, .. }) => {
            interpret_scope(scope, &mut data, instruction_index, sender)
        }
        _ => Err(gen_error_info(
            Interval { line: 0, column: 0 },
            format!("{} {}", name, ERROR_STEP_EXIST),
        )),
    }
}

pub fn parse_file(file: &str) -> Result<Flow, ErrorInfo> {
    // TODO: receive more than just the flow to be able to get real flow id
    Linter::clear();
    Linter::set_flow("default_flow");

    match parse_flow(file) {
        Ok(flow) => {
            let mut error = Vec::new();

            linter(&mut error);
            Linter::print_warnings();

            // TODO: tmp check until error handling
            match error.is_empty() {
                true => Ok(flow),
                false => Err(error.first().unwrap().to_owned()),
            }
        }
        Err(e) => Err(e),
    }
}

pub fn interpret(
    flow: &str,
    step_name: &str,
    context: ContextJson,
    event: &Event,
    sender: Option<mpsc::Sender<MSG>>,
) -> MessageData {
    let ast: Flow = match parse_file(flow) {
        Ok(flow) => flow,
        Err(e) => {
            StateContext::clear_state();
            StateContext::clear_rip();

            return MessageData::error_to_message(
                Err(gen_error_info(
                    Interval { line: 0, column: 0 },
                    format!("{} {}", ERROR_INVALID_FLOW, e.message),
                )),
                &sender,
            );
        }
    };

    let curl = Easy::new();
    let mut context = context.to_literal();
    let step_vars = match &context.hold {
        Some(hold) => get_hashmap(&hold.step_vars),
        None => HashMap::new(),
    };
    let instruction_index = if let Some(hold) = &context.hold {
        Some(hold.index)
    } else {
        None
    };
    let data = Data {
        ast: &ast,
        context: &mut context,
        event,
        curl,
        step_vars,
    };

    MessageData::error_to_message(
        execute_step(&ast, &step_name, data, instruction_index, &sender),
        &sender,
    )
}