diff --git a/src/macro/Expressions.cc b/src/macro/Expressions.cc index 57fc990f70a92b3f14e1d3926f494a7482661b6b..7b42ac567fc258c2609556e87d7fb022fbb23427 100644 --- a/src/macro/Expressions.cc +++ b/src/macro/Expressions.cc @@ -881,78 +881,7 @@ TrinaryOp::eval() } BaseTypePtr -ListComprehension::eval() -{ - ArrayPtr ap; - VariablePtr vp; - TuplePtr mt; - try - { - ap = dynamic_pointer_cast<Array>(c_set->eval()); - if (!ap) - throw StackTrace("ListComprehension", "The input set must evaluate to an array", location); - vp = dynamic_pointer_cast<Variable>(c_vars); - mt = dynamic_pointer_cast<Tuple>(c_vars); - if ((!vp && !mt) || (vp && mt)) - throw StackTrace("ListComprehension", "the output expression must be either " - "a tuple or a variable", location); - } - catch (StackTrace &ex) - { - ex.push("ListComprehension: ", location); - throw; - } - - vector<ExpressionPtr> values; - for (size_t i = 0; i < ap->size(); i++) - { - auto btp = dynamic_pointer_cast<BaseType>(ap->at(i)); - if (vp) - env.define(vp, btp); - else - if (btp->getType() == codes::BaseType::Tuple) - { - auto mt2 = dynamic_pointer_cast<Tuple>(btp); - if (mt->size() != mt2->size()) - throw StackTrace("ListComprehension", "The number of elements in the " - "input set tuple are not the same as the number of " - "elements in the output expression tuple", location); - - for (size_t j = 0; j < mt->size(); j++) - { - auto vp2 = dynamic_pointer_cast<Variable>(mt->at(j)); - if (!vp2) - throw StackTrace("ListComprehension", "Output expression tuple must be " - "comprised of variable names", location); - env.define(vp2, mt2->at(j)); - } - } - else - throw StackTrace("ListComprehension", "assigning to tuple in output expression " - "but input expression does not contain tuples", location); - - DoublePtr dp; - BoolPtr bp; - try - { - dp = dynamic_pointer_cast<Double>(c_when->eval()); - bp = dynamic_pointer_cast<Bool>(c_when->eval()); - if (!bp && !dp) - throw StackTrace("The condition must evaluate to a boolean or a double"); - } - catch (StackTrace &ex) - { - ex.push("ListComprehension", location); - throw; - } - if ((bp && *bp) || (dp && *dp)) - values.emplace_back(btp); - } - return make_shared<Array>(values, env); -} - -BaseTypePtr -ArrayComprehension::eval() +Comprehension::eval() { ArrayPtr input_set; VariablePtr vp; @@ -961,16 +890,16 @@ ArrayComprehension::eval() { input_set = dynamic_pointer_cast<Array>(c_set->eval()); if (!input_set) - throw StackTrace("ArrayComprehension", "The input set must evaluate to an array", location); + throw StackTrace("Comprehension", "The input set must evaluate to an array", location); vp = dynamic_pointer_cast<Variable>(c_vars); mt = dynamic_pointer_cast<Tuple>(c_vars); if ((!vp && !mt) || (vp && mt)) - throw StackTrace("ArrayComprehension", "the loop variables must be either " + throw StackTrace("Comprehension", "the loop variables must be either " "a tuple or a variable", location); } catch (StackTrace &ex) { - ex.push("ArrayComprehension: ", location); + ex.push("Comprehension: ", location); throw; } @@ -985,7 +914,7 @@ ArrayComprehension::eval() { auto mt2 = dynamic_pointer_cast<Tuple>(btp); if (mt->size() != mt2->size()) - throw StackTrace("ArrayComprehension", "The number of elements in the input " + throw StackTrace("Comprehension", "The number of elements in the input " " set tuple are not the same as the number of elements in " "the output expression tuple", location); @@ -993,17 +922,20 @@ ArrayComprehension::eval() { auto vp2 = dynamic_pointer_cast<Variable>(mt->at(j)); if (!vp2) - throw StackTrace("ArrayComprehension", "Output expression tuple must be " + throw StackTrace("Comprehension", "Output expression tuple must be " "comprised of variable names", location); env.define(vp2, mt2->at(j)); } } else - throw StackTrace("ArrayComprehension", "assigning to tuple in output expression " + throw StackTrace("Comprehension", "assigning to tuple in output expression " "but input expression does not contain tuples", location); if (!c_when) - values.emplace_back(c_expr->clone()->eval()); + if (!c_expr) + throw StackTrace("Comp", "DINGDONG",location); + else + values.emplace_back(c_expr->clone()->eval()); else { DoublePtr dp; @@ -1017,11 +949,14 @@ ArrayComprehension::eval() } catch (StackTrace &ex) { - ex.push("ArrayComprehension", location); + ex.push("Comprehension", location); throw; } if ((bp && *bp) || (dp && *dp)) - values.emplace_back(c_expr->clone()->eval()); + if (c_expr) + values.emplace_back(c_expr->clone()->eval()); + else + values.emplace_back(btp); } } return make_shared<Array>(values, env); @@ -1056,6 +991,17 @@ Function::clone() const noexcept return make_shared<Function>(name, args_copy, env, location); } +ExpressionPtr +Comprehension::clone() const noexcept +{ + if (c_expr && c_when) + return make_shared<Comprehension>(c_expr->clone(), c_vars->clone(), c_set->clone(), c_when->clone(), env, location); + else if (c_expr) + return make_shared<Comprehension>(c_expr->clone(), c_vars->clone(), c_set->clone(), env, location); + else + return make_shared<Comprehension>(true, c_vars->clone(), c_set->clone(), c_when->clone(), env, location); +} + string Array::to_string() const noexcept { @@ -1231,9 +1177,12 @@ TrinaryOp::to_string() const noexcept } string -ArrayComprehension::to_string() const noexcept +Comprehension::to_string() const noexcept { - string retval = "[" + c_expr->to_string() + " for " + c_vars->to_string() + " in " + c_set->to_string(); + string retval = "["; + if (c_expr) + retval += c_expr->to_string() + " for "; + retval += c_vars->to_string() + " in " + c_set->to_string(); if (c_when) retval += " when " + c_when->to_string(); return retval + "]"; @@ -1495,23 +1444,14 @@ TrinaryOp::print(ostream &output, bool matlab_output) const noexcept } void -ListComprehension::print(ostream &output, bool matlab_output) const noexcept +Comprehension::print(ostream &output, bool matlab_output) const noexcept { output << "["; - c_vars->print(output, matlab_output); - output << " in "; - c_set->print(output, matlab_output); - output << " when "; - c_when->print(output, matlab_output); - output << "]"; -} - -void -ArrayComprehension::print(ostream &output, bool matlab_output) const noexcept -{ - output << "["; - c_expr->print(output, matlab_output); - output << " for "; + if (c_expr) + { + c_expr->print(output, matlab_output); + output << " for "; + } c_vars->print(output, matlab_output); output << " in "; c_set->print(output, matlab_output); diff --git a/src/macro/Expressions.hh b/src/macro/Expressions.hh index 3e4a344f541ffea2e3b2db30174d6d710a69bb45..e49b98464b6de3130eb689e574bdb8f16d49b3fd 100644 --- a/src/macro/Expressions.hh +++ b/src/macro/Expressions.hh @@ -469,47 +469,41 @@ namespace macro }; - class ListComprehension final : public Expression - { - private: - const ExpressionPtr c_vars, c_set, c_when; - public: - ListComprehension(const ExpressionPtr c_vars_arg, - const ExpressionPtr c_set_arg, - const ExpressionPtr c_when_arg, - Environment &env_arg, const Tokenizer::location location_arg) : - Expression(env_arg, move(location_arg)), - c_vars{move(c_vars_arg)}, c_set{move(c_set_arg)}, c_when{move(c_when_arg)} { } - inline string to_string() const noexcept override { return "[" + c_vars->to_string() + " in " + c_set->to_string() + " when " + c_when->to_string() + "]"; } - void print(ostream &output, bool matlab_output = false) const noexcept override; - BaseTypePtr eval() override; - inline ExpressionPtr clone() const noexcept override { return make_shared<ListComprehension>(c_vars->clone(), c_set->clone(), c_when->clone(), env, location); } - }; - - - class ArrayComprehension final : public Expression + class Comprehension final : public Expression { + /* + * Filter: [c_vars IN c_set WHEN c_when] => c_expr == nullptr + * Map: [c_expr FOR c_vars IN c_set] => c_when == nullptr + * Filter + Map: [c_expr FOR c_vars IN c_set WHEN c_when] => all members assigned + */ private: const ExpressionPtr c_expr, c_vars, c_set, c_when; public: - ArrayComprehension(const ExpressionPtr c_expr_arg, - const ExpressionPtr c_vars_arg, - const ExpressionPtr c_set_arg, - const ExpressionPtr c_when_arg, - Environment &env_arg, const Tokenizer::location location_arg) : + Comprehension(const ExpressionPtr c_expr_arg, + const ExpressionPtr c_vars_arg, + const ExpressionPtr c_set_arg, + const ExpressionPtr c_when_arg, + Environment &env_arg, const Tokenizer::location location_arg) : Expression(env_arg, move(location_arg)), c_expr{move(c_expr_arg)}, c_vars{move(c_vars_arg)}, c_set{move(c_set_arg)}, c_when{move(c_when_arg)} { } - ArrayComprehension(const ExpressionPtr c_expr_arg, - const ExpressionPtr c_vars_arg, - const ExpressionPtr c_set_arg, - Environment &env_arg, const Tokenizer::location location_arg) : + Comprehension(const ExpressionPtr c_expr_arg, + const ExpressionPtr c_vars_arg, + const ExpressionPtr c_set_arg, + Environment &env_arg, const Tokenizer::location location_arg) : Expression(env_arg, move(location_arg)), c_expr{move(c_expr_arg)}, c_vars{move(c_vars_arg)}, c_set{move(c_set_arg)} { } + Comprehension(const bool filter_only_arg, + const ExpressionPtr c_vars_arg, + const ExpressionPtr c_set_arg, + const ExpressionPtr c_when_arg, + Environment &env_arg, const Tokenizer::location location_arg) : + Expression(env_arg, move(location_arg)), + c_vars{move(c_vars_arg)}, c_set{move(c_set_arg)}, c_when{move(c_when_arg)} { } string to_string() const noexcept override; void print(ostream &output, bool matlab_output = false) const noexcept override; BaseTypePtr eval() override; - inline ExpressionPtr clone() const noexcept override { return make_shared<ArrayComprehension>(c_expr->clone(), c_vars->clone(), c_set->clone(), c_when->clone(), env, location); } + ExpressionPtr clone() const noexcept override; }; } #endif diff --git a/src/macro/Parser.yy b/src/macro/Parser.yy index 739ad3d15cc229fc0d73ad338dd57e8c29e296b5..6aa08a39a6c8bc308d59711efbd967315a73fa14 100644 --- a/src/macro/Parser.yy +++ b/src/macro/Parser.yy @@ -304,11 +304,11 @@ expr : LPAREN expr RPAREN | LPAREN tuple_comma_expr RPAREN { $$ = make_shared<Tuple>($2, driver.env, @$); } | LBRACKET expr IN expr WHEN expr RBRACKET - { $$ = make_shared<ListComprehension>($2, $4, $6, driver.env, @$); } + { $$ = make_shared<Comprehension>(true, $2, $4, $6, driver.env, @$); } | LBRACKET expr FOR expr IN expr RBRACKET - { $$ = make_shared<ArrayComprehension>($2, $4, $6, driver.env, @$); } + { $$ = make_shared<Comprehension>($2, $4, $6, driver.env, @$); } | LBRACKET expr FOR expr IN expr WHEN expr RBRACKET - { $$ = make_shared<ArrayComprehension>($2, $4, $6, $8, driver.env, @$); } + { $$ = make_shared<Comprehension>($2, $4, $6, $8, driver.env, @$); } | NOT expr { $$ = make_shared<UnaryOp>(codes::UnaryOp::logical_not, $2, driver.env, @$); } | MINUS expr %prec UMINUS