Skip to content

Commit

Permalink
Merge pull request #347 from CSML-by-Clevy/feat/while_loop
Browse files Browse the repository at this point in the history
Feat/while loop
  • Loading branch information
amerelo committed Nov 8, 2021
2 parents b615fb4 + 16bcfa2 commit 3b15471
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 6 deletions.
9 changes: 9 additions & 0 deletions csml_interpreter/CSML/basic_test/while_loops.csml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
start:
do var = 0
while (var < 5) {
say var
do var = var + 1
}

goto end

1 change: 1 addition & 0 deletions csml_interpreter/src/data/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ pub enum Expr {
range: Interval,
},
ForEachExpr(Identifier, Option<Identifier>, Box<Expr>, Block, Interval),
WhileExpr(Box<Expr>, Block, Interval),
ComplexLiteral(Vec<Expr>, Interval),
MapExpr {
object: HashMap<String, Expr>,
Expand Down
7 changes: 4 additions & 3 deletions csml_interpreter/src/data/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub const L2_BRACE: &str = "{{";
pub const R2_BRACE: &str = "}}";

pub const FOREACH: &str = "foreach";
pub const WHILE: &str = "while";
pub const IF: &str = "if";
pub const ELSE: &str = "else";

Expand Down Expand Up @@ -112,18 +113,18 @@ pub const TYPES: &[&str] = &[
];

pub const RESERVED: &[&str] = &[
FOREACH, IF, ELSE, IMPORT, AS, IN, DO, FROM, EVENT, FLOW, FILE, STEP, SAY, USE, HOLD, GOTO,
FOREACH, WHILE, IF, ELSE, IMPORT, AS, IN, DO, FROM, EVENT, FLOW, FILE, STEP, SAY, USE, HOLD, GOTO,
MATCH, _METADATA, _MEMORY, _ENV, DEFAULT, REMEMBER, FORGET, TRUE, FALSE, NULL, BREAK,
COMPONENT,
];

pub const UTILISATION_RESERVED: &[&str] = &[
FOREACH, IF, ELSE, IMPORT, AS, DO, FLOW, STEP, SAY, USE, HOLD, GOTO, MATCH, REMEMBER, FORGET,
FOREACH, WHILE, IF, ELSE, IMPORT, AS, DO, FLOW, STEP, SAY, USE, HOLD, GOTO, MATCH, REMEMBER, FORGET,
BREAK, COMPONENT,
];

pub const ASSIGNATION_RESERVED: &[&str] = &[
FOREACH, IF, ELSE, IMPORT, AS, DO, EVENT, FLOW, STEP, SAY, USE, HOLD, GOTO, MATCH, REMEMBER,
FOREACH, WHILE , IF, ELSE, IMPORT, AS, DO, EVENT, FLOW, STEP, SAY, USE, HOLD, GOTO, MATCH, REMEMBER,
FORGET, _METADATA, _MEMORY, _ENV, TRUE, FALSE, NULL, BREAK, COMPONENT,
];

Expand Down
12 changes: 11 additions & 1 deletion csml_interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::data::position::Position;
use crate::data::{ast::*, Data, Hold, IndexInfo, Literal, MessageData, MSG};
use crate::error_format::*;
use crate::interpreter::{
ast_interpreter::{for_loop, match_actions, solve_if_statement},
ast_interpreter::{for_loop, while_loop, match_actions, solve_if_statement},
variable_handler::{expr_to_literal, interval::interval_from_expr},
};
use crate::parser::ExitCondition;
Expand Down Expand Up @@ -124,6 +124,16 @@ pub fn interpret_scope(
&sender,
)?
}
Expr::WhileExpr(expr, block, range) => {
message_data = while_loop(
expr,
block,
range,
message_data,
data,
&sender,
)?
}
e => {
return Err(gen_error_info(
Position::new(interval_from_expr(e), &data.context.flow),
Expand Down
2 changes: 2 additions & 0 deletions csml_interpreter/src/interpreter/ast_interpreter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod actions;
mod for_loop;
mod while_loop;
mod if_statement;

pub use actions::match_actions;
pub use for_loop::for_loop;
pub use while_loop::while_loop;
pub use if_statement::{evaluate_condition, solve_if_statement};
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::sync::mpsc;
////////////////////////////////////////////////////////////////////////////////

//TODO: add warning when comparing some objects
fn valid_condition(
pub fn valid_condition(
expr: &Expr,
data: &mut Data,
msg_data: &mut MessageData,
Expand Down
68 changes: 68 additions & 0 deletions csml_interpreter/src/interpreter/ast_interpreter/while_loop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::data::{
ast::*,
// hold::{
// hold_index_end_loop, hold_index_start_loop, hold_loop_decrs_index, hold_loop_incrs_index,
// },
// primitive::tools::get_array,
Data, MessageData, MSG,
};
use crate::error_format::*;
use crate::interpreter::{
ast_interpreter::if_statement::valid_condition,
interpret_scope
};
use crate::parser::ExitCondition;
use std::sync::mpsc;

////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTION
////////////////////////////////////////////////////////////////////////////////

pub fn while_loop(
cond: &Expr,
block: &Block,
_range_interval: &Interval,
mut msg_data: MessageData,
data: &mut Data,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<MessageData, ErrorInfo> {
// let literal = expr_to_literal(expr, false, None, data, &mut msg_data, sender)?;

// TODO: hold
// let mut array = get_array(literal, &data.context.flow, ERROR_FOREACH.to_owned())?;
// let mut skip_value = 0;
// let array = hold_index_start_loop(data, &mut array, &mut skip_value);

while valid_condition(cond, data, &mut msg_data, sender) {
// data.step_vars
// .insert(ident.ident.to_owned(), elem.to_owned());
// if let Some(index) = index {
// data.step_vars.insert(
// index.ident.to_owned(),
// PrimitiveInt::get_literal(for_loop_index as i64, elem.interval.to_owned()),
// );
// };

// hold_loop_incrs_index(data, for_loop_index + skip_value);
msg_data = msg_data + interpret_scope(block, data, sender)?;
// hold_loop_decrs_index(data);


match msg_data.exit_condition {
Some(ExitCondition::Break) => {
msg_data.exit_condition = None;
break;
}
Some(ExitCondition::Continue) => msg_data.exit_condition = None,
Some(_) => break,
None => {}
}
}

// hold_index_end_loop(data);
// data.step_vars.remove(&ident.ident);
// if let Some(index) = index {
// data.step_vars.remove(&index.ident);
// };
Ok(msg_data)
}
5 changes: 4 additions & 1 deletion csml_interpreter/src/interpreter/function_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::data::position::Position;
use crate::data::{ast::*, primitive::PrimitiveNull, Data, Literal, MessageData, MSG};
use crate::error_format::*;
use crate::interpreter::{
ast_interpreter::{for_loop, match_actions, solve_if_statement},
ast_interpreter::{for_loop, while_loop, match_actions, solve_if_statement},
variable_handler::{expr_to_literal, interval::interval_from_expr},
};
use crate::parser::ExitCondition;
Expand Down Expand Up @@ -36,6 +36,9 @@ fn interpret_function_scope(
Expr::ForEachExpr(ident, i, expr, block, range) => {
message_data = for_loop(ident, i, expr, block, range, message_data, data, sender)?
}
Expr::WhileExpr(expr, block, range) => {
message_data = while_loop(expr, block, range, message_data, data, sender)?
}
e => {
return Err(gen_error_info(
Position::new(interval_from_expr(e), &data.context.flow),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn interval_from_expr(expr: &Expr) -> Interval {
Expr::PostfixExpr(_p, expr) => interval_from_expr(expr), // RangeInterval ?
Expr::PathExpr { literal, .. } => interval_from_expr(literal),
Expr::ForEachExpr(_, _, _, _, range_interval) => *range_interval,
Expr::WhileExpr(_, _, range_interval) => *range_interval,
Expr::IdentExpr(ident) => ident.interval.to_owned(),
Expr::LitExpr { literal, .. } => literal.interval.to_owned(),
Expr::IfExpr(ifstmt) => interval_from_if_stmt(ifstmt),
Expand Down
5 changes: 5 additions & 0 deletions csml_interpreter/src/linter/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ fn validate_scope(
validate_scope(block, state, linter_info, step_breakers);
state.exit_loop();
}
Expr::WhileExpr(_expr, block, _range) => {
state.enter_loop();
validate_scope(block, state, linter_info, step_breakers);
state.exit_loop();
}
_ => {}
}
}
Expand Down
1 change: 1 addition & 0 deletions csml_interpreter/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod parse_built_in;
pub mod parse_closure;
pub mod parse_comments;
pub mod parse_foreach;
pub mod parse_while_loop;
pub mod parse_functions;
pub mod parse_goto;
pub mod parse_idents;
Expand Down
2 changes: 2 additions & 0 deletions csml_interpreter/src/parser/parse_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::parser::{
operator::parse_operator,
parse_comments::comment,
parse_foreach::parse_foreach,
parse_while_loop::parse_while,
parse_goto::parse_goto,
parse_previous::parse_previous,
parse_idents::{parse_idents_assignation, parse_idents_usage},
Expand Down Expand Up @@ -347,6 +348,7 @@ where
parse_debug,
parse_if,
parse_foreach,
parse_while,
// only accessible inside foreach or if scopes
parse_break,
parse_continue,
Expand Down
42 changes: 42 additions & 0 deletions csml_interpreter/src/parser/parse_while_loop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::data::{
ast::{Expr},
tokens::{Span, WHILE, L_PAREN, R_PAREN},
};
use crate::parser::operator::parse_operator;
use crate::parser::{
parse_comments::comment,
parse_scope::parse_scope,
tools::{get_interval},
};
use nom::{
bytes::complete::tag,
combinator::{cut},
error::ParseError,
sequence::preceded,
*,
};

////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTION
////////////////////////////////////////////////////////////////////////////////

pub fn parse_while<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Expr, E>
where
E: ParseError<Span<'a>>,
{
let (s, _) = preceded(comment, tag(WHILE))(s)?;
let (s, mut interval) = get_interval(s)?;

let (s, _) = cut(preceded(comment, tag(L_PAREN)))(s)?;
let (s, expr) = cut(parse_operator)(s)?;
let (s, _) = cut(preceded(comment, tag(R_PAREN)))(s)?;

let (s, block) = parse_scope(s)?;
let (s, end) = get_interval(s)?;
interval.add_end(end);

Ok((
s,
Expr::WhileExpr(Box::new(expr), block, interval),
))
}
4 changes: 4 additions & 0 deletions csml_interpreter/src/parser/state_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ pub fn count_commands(command: &mut Expr, index: &mut usize, info: &mut Instruct
info.index = *index;
count_scope_commands(block, index)
}
Expr::WhileExpr(_expr, block, _range) => {
info.index = *index;
count_scope_commands(block, index)
}
_ => {}
}

Expand Down
36 changes: 36 additions & 0 deletions csml_interpreter/tests/while_loop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
mod support;

use csml_interpreter::data::context::Context;
use csml_interpreter::data::event::Event;
use std::collections::HashMap;

use crate::support::tools::format_message;
use crate::support::tools::message_to_json_value;

use serde_json::Value;

#[test]
fn ok_while_loop() {
let data =
r#"
{
"messages":[
{"content":{ "text": "0" },"content_type":"text"},
{"content":{ "text": "1" },"content_type":"text"},
{"content":{ "text": "2" },"content_type":"text"},
{"content":{ "text": "3" },"content_type":"text"},
{"content":{ "text": "4" },"content_type":"text"}
],"memories":[]
}
"#;
let msg = format_message(
Event::new("payload", "", serde_json::json!({})),
Context::new(HashMap::new(), HashMap::new(), None, None, "start", "flow"),
"CSML/basic_test/while_loops.csml",
);

let v1: Value = message_to_json_value(msg);
let v2: Value = serde_json::from_str(data).unwrap();

assert_eq!(v1, v2)
}

0 comments on commit 3b15471

Please sign in to comment.