csml_interpreter/interpreter/ast_interpreter/
actions.rs

1use crate::data::data::PreviousInfo;
2use crate::data::position::Position;
3use crate::data::warnings::DisplayWarnings;
4use crate::data::{
5    ast::*,
6    context::ContextStepInfo,
7    data::Data,
8    literal::ContentType,
9    message::*,
10    primitive::{closure::capture_variables, PrimitiveNull, PrimitiveString},
11    Literal, Memory, MemoryType, MessageData, MSG,
12};
13use crate::error_format::*;
14use crate::interpreter::variable_handler::{
15    exec_path_actions, expr_to_literal,
16    forget_memories::{forget_scope_memories, remove_message_data_memories},
17    get_var_from_mem,
18    interval::*,
19    memory::*,
20    resolve_fn_args, search_goto_var_memory,
21};
22use crate::parser::ExitCondition;
23use std::collections::HashMap;
24use std::sync::mpsc;
25
26fn get_var_info<'a>(
27    expr: &'a Expr,
28    path: Option<&[(Interval, PathState)]>,
29    data: &'a mut Data,
30    msg_data: &mut MessageData,
31    sender: &Option<mpsc::Sender<MSG>>,
32) -> Result<
33    (
34        &'a mut Literal,
35        String,
36        MemoryType,
37        Option<Vec<(Interval, PathLiteral)>>,
38    ),
39    ErrorInfo,
40> {
41    match expr {
42        Expr::PathExpr { literal, path } => {
43            get_var_info(literal, Some(path), data, msg_data, sender)
44        }
45        Expr::IdentExpr(var) => match search_in_memory_type(var, data) {
46            Ok(_) => get_var_from_mem(
47                var.to_owned(),
48                &DisplayWarnings::On,
49                path,
50                data,
51                msg_data,
52                sender,
53            ),
54            // If variable doesn't exist, create the variable in the flow scope 'use' with NULL as value
55            // this is done in order to prevent stopping errors
56            Err(_) => {
57                let lit = PrimitiveNull::get_literal(var.interval.to_owned());
58
59                data.step_vars.insert(var.ident.to_owned(), lit);
60                get_var_from_mem(
61                    var.to_owned(),
62                    &DisplayWarnings::On,
63                    path,
64                    data,
65                    msg_data,
66                    sender,
67                )
68            }
69        },
70        e => Err(gen_error_info(
71            Position::new(interval_from_expr(e), &data.context.flow),
72            ERROR_GET_VAR_INFO.to_owned(),
73        )),
74    }
75}
76
77fn check_if_inserted_step<'a>(name: &str, interval: &Interval, data: &'a Data) -> Option<String> {
78    match data
79        .flow
80        .flow_instructions
81        .get_key_value(&InstructionScope::InsertStep(InsertStep {
82            name: name.to_owned(),
83            original_name: None,
84            from_flow: "".to_owned(),
85            interval: interval.clone(),
86        })) {
87        Some((InstructionScope::InsertStep(insert_step), _expr)) => {
88            Some(insert_step.from_flow.to_owned())
89        }
90        _ => None,
91    }
92}
93
94pub fn match_actions(
95    function: &ObjectType,
96    mut msg_data: MessageData,
97    data: &mut Data,
98    sender: &Option<mpsc::Sender<MSG>>,
99) -> Result<MessageData, ErrorInfo> {
100    match function {
101        ObjectType::Say(arg) => {
102            let lit =
103                expr_to_literal(arg, &DisplayWarnings::On, None, data, &mut msg_data, sender)?;
104
105            // check if it is secure variable
106            if lit.secure_variable {
107                let err = gen_error_info(
108                    Position::new(lit.interval, &data.context.flow),
109                    "Secure variable can not be displayed".to_owned(),
110                );
111
112                MSG::send_error_msg(&sender, &mut msg_data, Err(err));
113                Ok(msg_data)
114            } else {
115                let msg = Message::new(lit, &data.context.flow)?;
116                MSG::send(&sender, MSG::Message(msg.clone()));
117                Ok(Message::add_to_message(msg_data, MessageType::Msg(msg)))
118            }
119        }
120        ObjectType::Debug(args, interval) => {
121            let args = resolve_fn_args(args, data, &mut msg_data, &DisplayWarnings::On, sender)?;
122
123            let lit = args.args_to_debug(interval.to_owned());
124
125            // check if it is secure variable
126            if lit.secure_variable {
127                let err = gen_error_info(
128                    Position::new(lit.interval, &data.context.flow),
129                    "Secure variable can not be displayed".to_owned(),
130                );
131
132                MSG::send_error_msg(&sender, &mut msg_data, Err(err));
133                Ok(msg_data)
134            } else {
135                let msg = Message::new(lit, &data.context.flow)?;
136                MSG::send(&sender, MSG::Message(msg.clone()));
137                Ok(Message::add_to_message(msg_data, MessageType::Msg(msg)))
138            }
139        }
140        ObjectType::Log {
141            expr,
142            interval,
143            log_lvl,
144        } => {
145            let args = resolve_fn_args(expr, data, &mut msg_data, &DisplayWarnings::On, sender)?;
146            let log_msg = args.args_to_log();
147
148            MSG::send(
149                &sender,
150                MSG::Log {
151                    flow: data.context.flow.to_owned(),
152                    line: interval.start_line,
153                    message: log_msg,
154                    log_lvl: log_lvl.to_owned(),
155                },
156            );
157
158            Ok(msg_data)
159        }
160        ObjectType::Use(arg) => {
161            expr_to_literal(arg, &DisplayWarnings::On, None, data, &mut msg_data, sender)?;
162            Ok(msg_data)
163        }
164        ObjectType::Do(DoType::Update(assign_type, old, new)) => {
165            // ######################
166            // TODO:
167            // create a temporary scope, this is necessary in order to bypass de borrow checker
168            // in the future we need to refacto this code to avoid any scope copy like this
169            let (
170                tmp_flows,
171                tmp_extern_flows,
172                tmp_flow,
173                tmp_default_flow,
174                mut tmp_context,
175                tmp_event,
176                tmp_env,
177                tmp_loop_indexes,
178                tmp_loop_index,
179                mut tmp_step_count,
180                tmp_step_limit,
181                tmp_step_vars,
182                tmp_custom_component,
183                tmp_native_component,
184            ) = data.copy_scope();
185
186            let mut new_scope_data = Data::new(
187                &tmp_flows,
188                &tmp_extern_flows,
189                &tmp_flow,
190                tmp_default_flow,
191                &mut tmp_context,
192                &tmp_event,
193                &tmp_env,
194                tmp_loop_indexes,
195                tmp_loop_index,
196                &mut tmp_step_count,
197                tmp_step_limit,
198                tmp_step_vars,
199                data.previous_info.clone(),
200                &tmp_custom_component,
201                &tmp_native_component,
202            );
203            // #####################
204
205            let mut new_value =
206                expr_to_literal(new, &DisplayWarnings::On, None, data, &mut msg_data, sender)?;
207
208            // check if it is secure variable
209            if new_value.secure_variable {
210                let err = gen_error_info(
211                    Position::new(new_value.interval, &data.context.flow),
212                    "Assignation of secure variable is not allowed".to_owned(),
213                );
214
215                MSG::send_error_msg(&sender, &mut msg_data, Err(err));
216                return Ok(msg_data);
217            }
218
219            // only for closure capture the step variables
220            let memory: HashMap<String, Literal> = data.get_all_memories();
221            capture_variables(&mut &mut new_value, memory, &data.context.flow);
222
223            let (lit, name, mem_type, path) = get_var_info(old, None, data, &mut msg_data, sender)?;
224
225            let primitive = match assign_type {
226                AssignType::AdditionAssignment => {
227                    Some(lit.primitive.clone() + new_value.primitive.clone())
228                }
229                AssignType::SubtractionAssignment => {
230                    Some(lit.primitive.clone() - new_value.primitive.clone())
231                }
232                AssignType::DivisionAssignment => {
233                    Some(lit.primitive.clone() / new_value.primitive.clone())
234                }
235                AssignType::MultiplicationAssignment => {
236                    Some(lit.primitive.clone() * new_value.primitive.clone())
237                }
238                AssignType::RemainderAssignment => {
239                    Some(lit.primitive.clone() % new_value.primitive.clone())
240                }
241                AssignType::Assignment => None,
242            };
243
244            match primitive {
245                Some(Ok(primitive)) => {
246                    new_value = Literal {
247                        content_type: new_value.content_type,
248                        interval: new_value.interval,
249                        additional_info: None,
250                        secure_variable: false,
251                        primitive,
252                    };
253                }
254                Some(Err(err)) => {
255                    new_value = PrimitiveString::get_literal(&err, lit.interval);
256                    MSG::send_error_msg(
257                        &sender,
258                        &mut msg_data,
259                        Err(gen_error_info(
260                            Position::new(new_value.interval, &new_scope_data.context.flow),
261                            err,
262                        )),
263                    );
264                }
265                None => {}
266            }
267
268            //TODO: refacto memory update system
269
270            let (new_value, update) = if let MemoryType::Constant = mem_type {
271                MSG::send_error_msg(
272                    &sender,
273                    &mut msg_data,
274                    Err(gen_error_info(
275                        Position::new(new_value.interval, &new_scope_data.context.flow),
276                        format!("const variables are immutable"),
277                    )),
278                );
279
280                (None, false)
281            } else {
282                (Some(new_value), true)
283            };
284
285            exec_path_actions(
286                lit,
287                &DisplayWarnings::On,
288                &mem_type,
289                new_value,
290                &path,
291                &ContentType::get(&lit),
292                &mut new_scope_data,
293                &mut msg_data,
294                sender,
295            )?;
296
297            save_literal_in_mem(
298                lit.to_owned(),
299                name,
300                &mem_type,
301                update,
302                data,
303                &mut msg_data,
304                sender,
305            );
306
307            Ok(msg_data)
308        }
309        ObjectType::Do(DoType::Exec(expr)) => {
310            expr_to_literal(
311                expr,
312                &DisplayWarnings::On,
313                None,
314                data,
315                &mut msg_data,
316                sender,
317            )?;
318            Ok(msg_data)
319        }
320        ObjectType::Goto(GotoType::Step(step), interval) => {
321            let step = search_goto_var_memory(step, &mut msg_data, data, sender)?;
322
323            // previous flow/step
324            match data.previous_info {
325                Some(ref mut previous_info) => {
326                    previous_info.goto(data.context.flow.clone(), data.context.step.clone());
327                }
328                None => {
329                    data.previous_info = Some(PreviousInfo::new(
330                        data.context.flow.clone(),
331                        data.context.step.clone(),
332                    ))
333                }
334            }
335
336            let insert_from_flow = check_if_inserted_step(&step, interval, &data);
337
338            // current flow/step
339            data.context.step = match insert_from_flow {
340                Some(from_flow) => ContextStepInfo::InsertedStep {
341                    step: step.to_string(),
342                    flow: from_flow,
343                },
344                None => ContextStepInfo::Normal(step.to_string()),
345            };
346
347            MSG::send(
348                &sender,
349                MSG::Next {
350                    flow: None,
351                    step: Some(data.context.step.clone()),
352                    bot: None,
353                },
354            );
355
356            msg_data.exit_condition = Some(ExitCondition::Goto);
357
358            if step == "end" {
359                msg_data.exit_condition = Some(ExitCondition::End);
360            }
361
362            Ok(msg_data)
363        }
364        ObjectType::Goto(GotoType::Flow(flow), ..) => {
365            let flow = search_goto_var_memory(&flow, &mut msg_data, data, sender)?;
366
367            MSG::send(
368                &sender,
369                MSG::Next {
370                    flow: Some(flow.to_string()),
371                    step: None,
372                    bot: None,
373                },
374            );
375
376            // previous flow/step
377            match data.previous_info {
378                Some(ref mut previous_info) => {
379                    previous_info.goto(data.context.flow.clone(), data.context.step.clone());
380                }
381                None => {
382                    data.previous_info = Some(PreviousInfo::new(
383                        data.context.flow.clone(),
384                        data.context.step.clone(),
385                    ))
386                }
387            }
388            // current flow/step
389            data.context.step = ContextStepInfo::Normal("start".to_string());
390            data.context.flow = flow.to_string();
391
392            msg_data.exit_condition = Some(ExitCondition::Goto);
393
394            Ok(msg_data)
395        }
396        ObjectType::Goto(
397            GotoType::StepFlow {
398                step,
399                flow,
400                bot: None,
401            },
402            interval,
403        ) => {
404            let step = match step {
405                Some(step) => search_goto_var_memory(&step, &mut msg_data, data, sender)?,
406                None => "start".to_owned(), // default value start step
407            };
408            let flow = match flow {
409                Some(flow) => search_goto_var_memory(&flow, &mut msg_data, data, sender)?,
410                None => data.context.flow.to_owned(), // default value current flow
411            };
412
413            let mut flow_opt = Some(flow.clone());
414
415            msg_data.exit_condition = Some(ExitCondition::Goto);
416
417            if step == "end" {
418                msg_data.exit_condition = Some(ExitCondition::End);
419                flow_opt = None;
420            }
421
422            // previous flow/step
423            match data.previous_info {
424                Some(ref mut previous_info) => {
425                    previous_info.goto(data.context.flow.clone(), data.context.step.clone());
426                }
427                None => {
428                    data.previous_info = Some(PreviousInfo::new(
429                        data.context.flow.clone(),
430                        data.context.step.clone(),
431                    ))
432                }
433            }
434
435            // current flow/step
436            data.context.flow = flow.to_string();
437
438            let insert_from_flow = check_if_inserted_step(&step, interval, &data);
439
440            // current flow/step
441            data.context.step = match insert_from_flow {
442                Some(from_flow) => ContextStepInfo::InsertedStep {
443                    step: step.to_string(),
444                    flow: from_flow,
445                },
446                None => ContextStepInfo::Normal(step.to_string()),
447            };
448
449            MSG::send(
450                &sender,
451                MSG::Next {
452                    flow: flow_opt,
453                    step: Some(data.context.step.clone()),
454                    bot: None,
455                },
456            );
457
458            Ok(msg_data)
459        }
460
461        ObjectType::Goto(
462            GotoType::StepFlow {
463                step,
464                flow,
465                bot: Some(next_bot),
466            },
467            ..,
468        ) => {
469            let step = match step {
470                Some(step) => ContextStepInfo::UnknownFlow(search_goto_var_memory(
471                    &step,
472                    &mut msg_data,
473                    data,
474                    sender,
475                )?),
476                None => ContextStepInfo::Normal("start".to_owned()), // default value start step
477            };
478            let flow = match flow {
479                Some(flow) => search_goto_var_memory(&flow, &mut msg_data, data, sender).ok(),
480                None => None,
481            };
482
483            let bot = search_goto_var_memory(&next_bot, &mut msg_data, data, sender)?;
484
485            msg_data.exit_condition = Some(ExitCondition::End);
486
487            MSG::send(
488                &sender,
489                MSG::Next {
490                    step: Some(step),
491                    flow: flow,
492                    bot: Some(bot), // need to send previous flow / step / bot info
493                },
494            );
495
496            Ok(msg_data)
497        }
498
499        ObjectType::Previous(previous_type, _) => {
500            let flow_opt;
501            let mut step_opt = None;
502
503            match (previous_type, &mut data.previous_info) {
504                (PreviousType::Flow(_interval), Some(ref mut previous_info)) => {
505                    let tmp_f = previous_info.flow.clone();
506                    flow_opt = Some(tmp_f.clone());
507
508                    previous_info.flow = data.context.flow.clone();
509                    previous_info.step_at_flow =
510                        (data.context.step.clone(), data.context.flow.clone());
511
512                    data.context.flow = tmp_f;
513                    data.context.step = ContextStepInfo::Normal("start".to_string());
514                }
515                (PreviousType::Step(_interval), Some(ref mut previous_info)) => {
516                    let (tmp_s, tmp_f) = previous_info.step_at_flow.clone();
517                    flow_opt = Some(tmp_f.clone());
518                    step_opt = Some(tmp_s.clone());
519
520                    if data.context.flow != tmp_f {
521                        previous_info.flow = tmp_f.clone();
522                    }
523                    previous_info.step_at_flow =
524                        (data.context.step.clone(), data.context.flow.clone());
525
526                    data.context.flow = tmp_f;
527                    data.context.step = tmp_s;
528                }
529                (_, None) => {
530                    flow_opt = None;
531                    step_opt = Some(ContextStepInfo::Normal("end".to_owned()));
532
533                    data.context.step = ContextStepInfo::Normal("end".to_string());
534                }
535            }
536
537            msg_data.exit_condition = Some(ExitCondition::Goto);
538
539            MSG::send(
540                &sender,
541                MSG::Next {
542                    flow: flow_opt,
543                    step: step_opt,
544                    bot: None,
545                },
546            );
547
548            Ok(msg_data)
549        }
550        ObjectType::Remember(name, variable) => {
551            let mut new_value = expr_to_literal(
552                variable,
553                &DisplayWarnings::On,
554                None,
555                data,
556                &mut msg_data,
557                sender,
558            )?;
559
560            // check if it is secure variable
561            if new_value.secure_variable {
562                let err = gen_error_info(
563                    Position::new(new_value.interval, &data.context.flow),
564                    "Assignation of secure variable is not allowed".to_owned(),
565                );
566
567                MSG::send_error_msg(&sender, &mut msg_data, Err(err));
568                return Ok(msg_data);
569            }
570
571            // only for closure capture the step variables
572            let memory: HashMap<String, Literal> = data.get_all_memories();
573            capture_variables(&mut &mut new_value, memory, &data.context.flow);
574
575            msg_data.add_to_memory(&name.ident, new_value.clone());
576
577            MSG::send(
578                &sender,
579                MSG::Remember(Memory::new(name.ident.to_owned(), new_value.clone())),
580            );
581
582            data.context
583                .current
584                .insert(name.ident.to_owned(), new_value);
585            Ok(msg_data)
586        }
587        ObjectType::Forget(memory, _interval) => {
588            // delete memories form message data
589            remove_message_data_memories(&memory, &mut msg_data);
590            // delete memory from current scope
591            forget_scope_memories(&memory, data);
592
593            MSG::send(&sender, MSG::Forget(memory.to_owned()));
594
595            Ok(msg_data)
596        }
597
598        reserved => Err(gen_error_info(
599            Position::new(interval_from_reserved_fn(reserved), &data.context.flow),
600            ERROR_START_INSTRUCTIONS.to_owned(),
601        )),
602    }
603}